From ca745ca470b7b1836290dda0b3048444e07a5a25 Mon Sep 17 00:00:00 2001 From: Adam Black Date: Fri, 21 May 2021 22:32:55 +0100 Subject: [PATCH] Removed functions from server.js and put them in their own controllers. Updated .gitignore to ignore dbs/configs/.idea files --- .gitignore | 3 + controllers/authentication.js | 32 ++++- controllers/helpers.js | 51 +++++++ controllers/index.js | 13 +- controllers/storage.js | 129 +++++++++++++++++ models/index.js | 32 ++++- models/users.js | 21 +++ server.js | 252 +++++++--------------------------- 8 files changed, 315 insertions(+), 218 deletions(-) create mode 100644 controllers/helpers.js create mode 100644 controllers/storage.js create mode 100644 models/users.js diff --git a/.gitignore b/.gitignore index a573546..3d58cda 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,6 @@ package-lock.json database.sqlite config.js .vscode +.idea +database.sqlite +config.js \ No newline at end of file diff --git a/controllers/authentication.js b/controllers/authentication.js index 5975706..50889dc 100644 --- a/controllers/authentication.js +++ b/controllers/authentication.js @@ -1,6 +1,7 @@ const jwt = require('jsonwebtoken'); - +let models; +let logger; async function validateJWT(token, key) { @@ -14,6 +15,31 @@ async function validateJWT(token, key) { } -module.exports = { - validateJWT: validateJWT +async function getAuthenticatedAccount(req, res) { + const sessionCookie = (req.signedCookies !== undefined ? req.signedCookies.session : null); + if (!sessionCookie || sessionCookie.expires <= Date.now()) { return null; } + const email = sessionCookie.account.trim().toLowerCase(); + + + // don't need to wait for this, logging a ping if a banned user attempts to sign in + + // TODO stop storing emails in the cookie + const account = await models.users.getAccountFromEmail(email) + + if (!account || account.banned) { + res ? res.clearCookie('session') : logger.warn(`getAuthenticatedAccount unable to clear banned user (${account.email}) cookie, res not passed`); + return null; + } + return account; +} + + +module.exports = (_models, _logger) => { + models = _models; + logger = _logger; + + return { + validateJWT: validateJWT, + getAuthenticatedAccount: getAuthenticatedAccount + } } diff --git a/controllers/helpers.js b/controllers/helpers.js new file mode 100644 index 0000000..b0d0f18 --- /dev/null +++ b/controllers/helpers.js @@ -0,0 +1,51 @@ +let models; +let logger; + + +function formatDuration(durationSeconds) { + durationSeconds = Math.round(durationSeconds); + const secs = durationSeconds % 60; + let mins = Math.floor(durationSeconds / 60); + const hours = Math.floor(mins / 60); + mins = mins % 60; + + let response = ''; + if (hours > 0) response += hours + 'h '; + if (hours > 0 || mins > 0) response += mins + 'm '; + response += secs + 's'; + return response; +} + + +function simpleStringify(object) { + let simpleObject = {}; + for (var prop in object) { + if (!object.hasOwnProperty(prop)) { + continue; + } + if (typeof (object[prop]) == 'object') { + continue; + } + if (typeof (object[prop]) == 'function') { + continue; + } + simpleObject[prop] = object[prop]; + } + return JSON.stringify(simpleObject); // returns cleaned up JSON +} + + +function formatDate(timestampMs) { + return new Date(timestampMs).toISOString().replace(/T/, ' ').replace(/\..+/, ''); +} + + + +module.exports = (_models, _logger) => { + models = _models; + logger = _logger; + + return { + formatDuration, simpleStringify, formatDate + } +} diff --git a/controllers/index.js b/controllers/index.js index bda6450..660a5e5 100644 --- a/controllers/index.js +++ b/controllers/index.js @@ -1,6 +1,13 @@ +const config = require('./../config'); +module.exports = async (models, logger) => { -module.exports = { - authenticationController: require('./authentication') -} \ No newline at end of file + + return { + authentication: require('./authentication')(models, logger), + helpers: require('./helpers')(models, logger), + storage: require('./storage')(models, logger) + } + +} diff --git a/controllers/storage.js b/controllers/storage.js new file mode 100644 index 0000000..b0ff79c --- /dev/null +++ b/controllers/storage.js @@ -0,0 +1,129 @@ +const config = require('./../config'); +const path = require('path'); +const fs = require('fs') + +let models; +let logger; + +let totalStorageUsed; + +function initializeStorage() { + var verifiedPath = mkDirByPathSync(config.storagePath, {isRelativeToScript: (config.storagePath.indexOf("/") === 0 ? false : true)}); + if (verifiedPath != null) + logger.info("Verified storage path " + verifiedPath); + else { + logger.error("Unable to verify storage path '" + config.storagePath + "', check filesystem / permissions"); + process.exit(); + } +} + +function mkDirByPathSync(targetDir, {isRelativeToScript = false} = {}) { + const sep = path.sep; + const initDir = path.isAbsolute(targetDir) ? sep : ''; + + // TODO does this break anything? Commented out code will create a folder in the /controllers directory, defined __basedir as a global var in server.js + const baseDir = __basedir; //isRelativeToScript ? __dirname : '.'; + + return targetDir.split(sep).reduce((parentDir, childDir) => { + const curDir = path.resolve(baseDir, parentDir, childDir); + try { + fs.mkdirSync(curDir); + } catch (err) { + console.debug(err); + if (err.code === 'EEXIST') { // curDir already exists! + return curDir; + } + + // To avoid `EISDIR` error on Mac and `EACCES`-->`ENOENT` and `EPERM` on Windows. + if (err.code === 'ENOENT') { // Throw the original parentDir error on curDir `ENOENT` failure. + logger.error(`EACCES: permission denied, mkdir '${parentDir}'`); + return null; + } + + const caughtErr = ['EACCES', 'EPERM', 'EISDIR'].indexOf(err.code) > -1; + if (!caughtErr || (caughtErr && curDir === path.resolve(targetDir))) { + logger.error("'EACCES', 'EPERM', 'EISDIR' during mkdir"); + return null; + } + + } + + return curDir; + }, initDir); +} + + +function writeFileSync(path, buffer, permission) { + let fileDescriptor; + try { + fileDescriptor = fs.openSync(path, 'w', permission); + } catch (e) { + fs.chmodSync(path, permission); + fileDescriptor = fs.openSync(path, 'w', permission); + } + + if (fileDescriptor) { + fs.writeSync(fileDescriptor, buffer, 0, buffer.length, 0); + fs.closeSync(fileDescriptor); + logger.info("writeFileSync wiriting to '" + path + "' successful"); + return true; + } + logger.error("writeFileSync writing to '" + path + "' failed"); + return false; +} + +function moveUploadedFile(buffer, directory, filename) { + logger.info(`moveUploadedFile called with ${filename} -> ${directory}'`); + + if (directory.indexOf("..") >= 0 || filename.indexOf("..") >= 0) { + logger.error("moveUploadedFile failed, .. in directory or filename"); + return false; + } + + if (config.storagePath.lastIndexOf("/") !== config.storagePath.length - 1) + directory = '/' + directory; + if (directory.lastIndexOf("/") !== directory.length - 1) + directory = directory + '/'; + + const finalPath = mkDirByPathSync(config.storagePath + directory, {isRelativeToScript: (config.storagePath.indexOf("/") === 0 ? false : true)}); + if (finalPath && finalPath.length > 0) { + if (writeFileSync(finalPath + "/" + filename, buffer, 0o660)) { + logger.info("moveUploadedFile successfully written '" + (finalPath + "/" + filename) + "'"); + return finalPath + "/" + filename; + } + logger.error("moveUploadedFile failed to writeFileSync"); + return false; + } + logger.error("moveUploadedFile invalid final path, check permissions to create / write '" + (config.storagePath + directory) + "'"); + return false; +} + + +async function updateTotalStorageUsed() { + const verifiedPath = mkDirByPathSync(config.storagePath, {isRelativeToScript: (config.storagePath.indexOf("/") === 0 ? false : true)}); + if (verifiedPath !== null) { + try { + totalStorageUsed = execSync("du -hs " + verifiedPath + " | awk -F'\t' '{print $1;}'").toString(); + } catch (exception) { + totalStorageUsed = "Unsupported Platform"; + logger.debug(`Unable to calculate storage used, only supported on systems with 'du' available`) + } + } + setTimeout(function () { + updateTotalStorageUsed(); + }, 120000); // update the used storage each 120 seconds +} + +async function getTotalStorageUsed() { + return totalStorageUsed; +} + + +module.exports = (_models, _logger) => { + models = _models; + logger = _logger; + + return { + initializeStorage, mkDirByPathSync, writeFileSync, moveUploadedFile, updateTotalStorageUsed, getTotalStorageUsed + } +} diff --git a/models/index.js b/models/index.js index 012ceec..20e2a8c 100644 --- a/models/index.js +++ b/models/index.js @@ -2,11 +2,7 @@ const sqlite3 = require('sqlite3') const {open} = require('sqlite') const config = require('./../config'); - - - -module.exports = async (logger) => { - let db; +async function validateDatabase(db, logger) { try { db = await open({ filename: config.databaseFile, @@ -22,12 +18,36 @@ module.exports = async (logger) => { logger.error(exception); process.exit(); } +} + + + + +module.exports = async (logger) => { + let db; + + try { + db = await open({ + filename: config.databaseFile, + driver: sqlite3.Database, + mode: sqlite3.OPEN_READWRITE + }); + + } catch (exception) { + logger.error(exception); + process.exit(); + } + + // I'm not sure we _really_ need to wait for this, since it'll exit the application if it's invalid anyway. + + await validateDatabase(db, logger); return { db, models: { - drivesModel: require('./drives')(db) + drivesModel: require('./drives')(db), + users: require('./users')(db), } } } \ No newline at end of file diff --git a/models/users.js b/models/users.js new file mode 100644 index 0000000..2c1bc42 --- /dev/null +++ b/models/users.js @@ -0,0 +1,21 @@ +let db; + +async function userPing(email) { + return await db.run('UPDATE accounts SET last_ping = ? WHERE email = ?', Date.now(), email); +} + +async function getAccountFromEmail(email) { + return await db.get('SELECT * FROM accounts WHERE LOWER(email) = ?', email); + +} + + + +module.exports = (_db) => { + db = _db; + + return { + userPing, + getAccountFromEmail + } +} \ No newline at end of file diff --git a/server.js b/server.js index 3044bc1..e054ab6 100644 --- a/server.js +++ b/server.js @@ -3,202 +3,35 @@ const fs = require('fs'); const path = require('path'); const crypto = require('crypto'); const log4js = require('log4js'); - - - const lockfile = require('proper-lockfile'); - -var http = require('http'); -var https = require('https'); - +const http = require('http'); +const https = require('https'); const express = require('express'); const cors = require('cors'); const bodyParser = require('body-parser'); const cookieParser = require('cookie-parser'); const jwt = require('jsonwebtoken'); - const sendmail = require('sendmail')(); - const htmlspecialchars = require('htmlspecialchars'); - const dirTree = require("directory-tree"); const execSync = require('child_process').execSync; - log4js.configure({ appenders: {logfile: {type: "file", filename: "server.log"}, out: {type: "console"}}, categories: {default: {appenders: ['out', 'logfile'], level: 'info'}} }); -var logger = log4js.getLogger('default'); +const logger = log4js.getLogger('default'); +// TODO evaluate if this is the best way to determine the root of project +global.__basedir = __dirname; let models = require('./models/index'); +let controllers = require('./controllers'); let db; -let {authenticationController} = require('./controllers'); -var totalStorageUsed = null; // global variable that is regularly updated in the background to track the total used storage - - - -function initializeStorage() { - var verifiedPath = mkDirByPathSync(config.storagePath, {isRelativeToScript: (config.storagePath.indexOf("/") === 0 ? false : true)}); - if (verifiedPath != null) - logger.info("Verified storage path " + verifiedPath); - else { - logger.error("Unable to verify storage path '" + config.storagePath + "', check filesystem / permissions"); - process.exit(); - } -} - -function validateJWTToken(token, publicKey) { - try { - var decoded = jwt.verify(token.replace("JWT ", ""), publicKey, {algorithms: ['RS256']}); - return decoded; - } catch (exception) { - logger.error(exception); - } - return null; -} - -function formatDate(timestampMs) { - return new Date(timestampMs).toISOString().replace(/T/, ' ').replace(/\..+/, ''); -} - -function formatDuration(durationSeconds) { - durationSeconds = Math.round(durationSeconds); - var secs = durationSeconds % 60; - var mins = Math.floor(durationSeconds / 60); - var hours = Math.floor(mins / 60); - mins = mins % 60; - - var response = ''; - if (hours > 0) response += hours + 'h '; - if (hours > 0 || mins > 0) response += mins + 'm '; - response += secs + 's'; - return response; -} - -function mkDirByPathSync(targetDir, {isRelativeToScript = false} = {}) { - const sep = path.sep; - const initDir = path.isAbsolute(targetDir) ? sep : ''; - const baseDir = isRelativeToScript ? __dirname : '.'; - - return targetDir.split(sep).reduce((parentDir, childDir) => { - const curDir = path.resolve(baseDir, parentDir, childDir); - try { - fs.mkdirSync(curDir); - } catch (err) { - if (err.code === 'EEXIST') { // curDir already exists! - return curDir; - } - - // To avoid `EISDIR` error on Mac and `EACCES`-->`ENOENT` and `EPERM` on Windows. - if (err.code === 'ENOENT') { // Throw the original parentDir error on curDir `ENOENT` failure. - logger.error(`EACCES: permission denied, mkdir '${parentDir}'`); - return null; - } - - const caughtErr = ['EACCES', 'EPERM', 'EISDIR'].indexOf(err.code) > -1; - if (!caughtErr || (caughtErr && curDir === path.resolve(targetDir))) { - logger.error("'EACCES', 'EPERM', 'EISDIR' during mkdir"); - return null; - } - } - - return curDir; - }, initDir); -} - -function simpleStringify(object) { - var simpleObject = {}; - for (var prop in object) { - if (!object.hasOwnProperty(prop)) { - continue; - } - if (typeof (object[prop]) == 'object') { - continue; - } - if (typeof (object[prop]) == 'function') { - continue; - } - simpleObject[prop] = object[prop]; - } - return JSON.stringify(simpleObject); // returns cleaned up JSON -} - -function writeFileSync(path, buffer, permission) { - var fileDescriptor; - try { - fileDescriptor = fs.openSync(path, 'w', permission); - } catch (e) { - fs.chmodSync(path, permission); - fileDescriptor = fs.openSync(path, 'w', permission); - } - - if (fileDescriptor) { - fs.writeSync(fileDescriptor, buffer, 0, buffer.length, 0); - fs.closeSync(fileDescriptor); - logger.info("writeFileSync wiriting to '" + path + "' successful"); - return true; - } - logger.error("writeFileSync writing to '" + path + "' failed"); - return false; -} - -function moveUploadedFile(buffer, directory, filename) { - logger.info("moveUploadedFile called with '" + filename + "' -> '" + directory + "'"); - - if (directory.indexOf("..") >= 0 || filename.indexOf("..") >= 0) { - logger.error("moveUploadedFile failed, .. in directory or filename"); - return false; - } - - if (config.storagePath.lastIndexOf("/") !== config.storagePath.length - 1) - directory = '/' + directory; - if (directory.lastIndexOf("/") !== directory.length - 1) - directory = directory + '/'; - - var finalPath = mkDirByPathSync(config.storagePath + directory, {isRelativeToScript: (config.storagePath.indexOf("/") === 0 ? false : true)}); - if (finalPath && finalPath.length > 0) { - if (writeFileSync(finalPath + "/" + filename, buffer, 0o660)) { - logger.info("moveUploadedFile successfully written '" + (finalPath + "/" + filename) + "'"); - return finalPath + "/" + filename; - } - logger.error("moveUploadedFile failed to writeFileSync"); - return false; - } - logger.error("moveUploadedFile invalid final path, check permissions to create / write '" + (config.storagePath + directory) + "'"); - return false; -} - -async function getAuthenticatedAccount(req) { - - var sessionCookie = (req.signedCookies !== undefined ? req.signedCookies.session : null); - if (!sessionCookie || sessionCookie.expires <= Date.now()) { - return null; - } - - const account = await db.get('SELECT * FROM accounts WHERE LOWER(email) = ?', sessionCookie.account.trim().toLowerCase()); - if (!account || account.banned) { - res.clearCookie('session'); - return null; - } - const result = await db.run('UPDATE accounts SET last_ping = ? WHERE email = ?', Date.now(), account.email); - return account; -} - -function updateTotalStorageUsed() { - var verifiedPath = mkDirByPathSync(config.storagePath, {isRelativeToScript: (config.storagePath.indexOf("/") === 0 ? false : true)}); - if (verifiedPath !== null) { - totalStorageUsed = execSync("du -hs " + verifiedPath + " | awk -F'\t' '{print $1;}'").toString(); - } - setTimeout(function () { - updateTotalStorageUsed(); - }, 120000); // update the used storage each 120 seconds -} - +// TODO function runAsyncWrapper(callback) { return function (req, res, next) { callback(req, res, next) @@ -207,6 +40,8 @@ function runAsyncWrapper(callback) { } + + // CREATE OUR SERVER EXPRESS APP const app = express(); app.use(cors()); @@ -214,7 +49,8 @@ app.use(cookieParser(config.applicationSalt)) app.use('/favicon.ico', express.static('static/favicon.ico')); -app.use(config.baseDriveDownloadPathMapping, express.static(config.storagePath)); +//app.use(config.baseDriveDownloadPathMapping, express.static(config.storagePath)); + app.use('/.well-known', express.static('.well-known')); // DRIVE & BOOT/CRASH LOG FILE UPLOAD HANDLING @@ -243,7 +79,7 @@ app.put('/backend/post_upload', bodyParser.raw({ } else { logger.info("HTTP.PUT /backend/post_upload permissions checked, calling moveUploadedFile"); - var moveResult = moveUploadedFile(buf, directory, filename); + var moveResult = controllers.storage.moveUploadedFile(buf, directory, filename); if (moveResult === false) { logger.error("HTTP.PUT /backend/post_upload moveUploadedFile failed"); res.status(500); @@ -267,7 +103,7 @@ app.put('/backend/post_upload', bodyParser.raw({ } else { logger.info("HTTP.PUT /backend/post_upload permissions checked, calling moveUploadedFile"); - var moveResult = moveUploadedFile(buf, directory, filename); + var moveResult = controllers.storage.moveUploadedFile(buf, directory, filename); if (moveResult === false) { logger.error("HTTP.PUT /backend/post_upload moveUploadedFile failed"); res.status(500); @@ -298,7 +134,7 @@ app.put('/backend/post_upload', bodyParser.raw({ return res.send('Unauthorized.').status(400) } - let decoded = device.public_key ? await authenticationController.validateJWT(req.headers.authorization, device.public_key) : null; + let decoded = device.public_key ? await controllers.authentication.validateJWT(req.headers.authorization, device.public_key) : null; if ((decoded == undefined || decoded.identity !== req.params.dongleId)) { logger.info(`HTTP.UPLOAD_URL JWT authorization failed, token: ${auth} device: ${JSON.stringify(device)}, decoded: ${JSON.stringify(decoded)}`); @@ -423,7 +259,7 @@ app.put('/backend/post_upload', bodyParser.raw({ return; } - var decoded = validateJWTToken(req.query.register_token, public_key); + var decoded = controllers.authentication.validateJWT(req.query.register_token, public_key); if (decoded == null || decoded.register == undefined) { logger.error("HTTP.V2.PILOTAUTH JWT token is invalid (" + JSON.stringify(decoded) + ")"); @@ -542,7 +378,7 @@ app.put('/backend/post_upload', bodyParser.raw({ app.get('/useradmin', runAsyncWrapper(async (req, res) => { - const account = await getAuthenticatedAccount(req); + const account = await controllers.authentication.getAuthenticatedAccount(req, res); if (account != null) { res.redirect('/useradmin/overview'); return; @@ -565,7 +401,7 @@ app.put('/backend/post_upload', bodyParser.raw({ 'Accounts: ' + accounts.num + ' | ' + 'Devices: ' + devices.num + ' | ' + 'Drives: ' + drives.num + ' | ' + - 'Storage Used: ' + (totalStorageUsed !== null ? totalStorageUsed : '--') + '

' + config.welcomeMessage + ''); + 'Storage Used: ' + (await controllers.storage.getTotalStorageUsed() !== null ? await controllers.storage.getTotalStorageUsed() : '--') + '

' + config.welcomeMessage + ''); })), @@ -576,7 +412,7 @@ app.put('/backend/post_upload', bodyParser.raw({ return; } - const authAccount = await getAuthenticatedAccount(req); + const authAccount = await controllers.authentication.getAuthenticatedAccount(req, res); if (authAccount != null) { res.redirect('/useradmin/overview'); return; @@ -657,7 +493,7 @@ app.put('/backend/post_upload', bodyParser.raw({ return; } - const account = await getAuthenticatedAccount(req); + const account = await controllers.authentication.getAuthenticatedAccount(req, res); if (account != null) { res.redirect('/useradmin/overview'); return; @@ -678,7 +514,7 @@ app.put('/backend/post_upload', bodyParser.raw({ app.get('/useradmin/overview', runAsyncWrapper(async (req, res) => { - const account = await getAuthenticatedAccount(req); + const account = await controllers.authentication.getAuthenticatedAccount(req, res); if (account == null) { res.redirect('/useradmin?status=' + encodeURIComponent('Invalid or expired session')); return; @@ -691,14 +527,14 @@ app.put('/backend/post_upload', bodyParser.raw({ `

Account Overview

Account: #` + account.id + `
Email: ` + account.email + `
- Created: ` + formatDate(account.created) + `

+ Created: ` + controllers.helpers.formatDate(account.created) + `

Devices:
`; for (var i in devices) { - response += ''; + response += ''; } response += `
dongle_iddevice_typecreatedlast_pingstorage_used
' + devices[i].dongle_id + '' + devices[i].device_type + '' + formatDate(devices[i].created) + '' + formatDate(devices[i].last_ping) + '' + devices[i].storage_used + ' MB
' + devices[i].dongle_id + '' + devices[i].device_type + '' + controllers.helpers.formatDate(devices[i].created) + '' + controllers.helpers.formatDate(devices[i].last_ping) + '' + devices[i].storage_used + ' MB

@@ -720,7 +556,7 @@ app.put('/backend/post_upload', bodyParser.raw({ app.get('/useradmin/unpair_device/:dongleId', runAsyncWrapper(async (req, res) => { - const account = await getAuthenticatedAccount(req); + const account = await controllers.authentication.getAuthenticatedAccount(req, res); if (account == null) { res.redirect('/useradmin?status=' + encodeURIComponent('Invalid or expired session')); return; @@ -745,7 +581,7 @@ app.put('/backend/post_upload', bodyParser.raw({ app.post('/useradmin/pair_device', bodyParser.urlencoded({extended: true}), runAsyncWrapper(async (req, res) => { - const account = await getAuthenticatedAccount(req); + const account = await controllers.authentication.getAuthenticatedAccount(req, res); if (account == null) { res.redirect('/useradmin?status=' + encodeURIComponent('Invalid or expired session')); return; @@ -757,7 +593,7 @@ app.put('/backend/post_upload', bodyParser.raw({ if (device == null) { res.redirect('/useradmin/overview?linkstatus=' + encodeURIComponent('Device not registered on Server')); } - var decoded = validateJWTToken(qrCodeParts[2], device.public_key); + var decoded = controllers.authentication.validateJWT(qrCodeParts[2], device.public_key); if (decoded == null || decoded.pair == undefined) { res.redirect('/useradmin/overview?linkstatus=' + encodeURIComponent('Device QR Token is invalid or has expired')); } @@ -776,7 +612,7 @@ app.put('/backend/post_upload', bodyParser.raw({ app.get('/useradmin/device/:dongleId', runAsyncWrapper(async (req, res) => { - const account = await getAuthenticatedAccount(req); + const account = await controllers.authentication.getAuthenticatedAccount(req, res); if (account == null) { res.redirect('/useradmin?status=' + encodeURIComponent('Invalid or expired session')); return; @@ -836,8 +672,8 @@ app.put('/backend/post_upload', bodyParser.raw({ Type: ` + device.device_type + `
Serial: ` + device.serial + `
IMEI: ` + device.imei + `
- Registered: ` + formatDate(device.created) + `
- Last Ping: ` + formatDate(device.last_ping) + `
+ Registered: ` + controllers.helpers.formatDate(device.created) + `
+ Last Ping: ` + controllers.helpers.formatDate(device.last_ping) + `
Public Key:
` + device.public_key.replace(/\r?\n|\r/g, "
") + `

Stored Drives: ` + drives.length + `
@@ -850,7 +686,7 @@ app.put('/backend/post_upload', bodyParser.raw({ datefilesize `; for (var i = 0; i < Math.min(5, bootlogFiles.length); i++) { - response += `` + formatDate(bootlogFiles[i].date) + `` + bootlogFiles[i].name + `` + bootlogFiles[i].size + ``; + response += `` + controllers.helpers.formatDate(bootlogFiles[i].date) + `` + bootlogFiles[i].name + `` + bootlogFiles[i].size + ``; } response += `

`; @@ -859,7 +695,7 @@ app.put('/backend/post_upload', bodyParser.raw({ datefilesize `; for (var i = 0; i < Math.min(5, crashlogFiles.length); i++) { - response += `` + formatDate(crashlogFiles[i].date) + `` + crashlogFiles[i].name + `` + crashlogFiles[i].size + ``; + response += `` + controllers.helpers.formatDate(crashlogFiles[i].date) + `` + crashlogFiles[i].name + `` + crashlogFiles[i].size + ``; } response += `

`; @@ -870,7 +706,7 @@ app.put('/backend/post_upload', bodyParser.raw({ `; for (var i in drives) { - response += '' + (drives[i].is_preserved ? '' : '') + drives[i].identifier + (drives[i].is_preserved ? '' : '') + '' + Math.round(drives[i].filesize / 1024) + ' MiB' + formatDuration(drives[i].duration) + '' + Math.round(drives[i].distance_meters / 1000) + ' km' + drives[i].upload_complete + '' + drives[i].is_processed + '' + formatDate(drives[i].created) + '' + '[delete]' + (drives[i].is_preserved ? '' : '  [preserve]') + ''; + response += '' + (drives[i].is_preserved ? '' : '') + drives[i].identifier + (drives[i].is_preserved ? '' : '') + '' + Math.round(drives[i].filesize / 1024) + ' MiB' + controllers.helpers.formatDuration(drives[i].duration) + '' + Math.round(drives[i].distance_meters / 1000) + ' km' + drives[i].upload_complete + '' + drives[i].is_processed + '' + controllers.helpers.formatDate(drives[i].created) + '' + '[delete]' + (drives[i].is_preserved ? '' : '  [preserve]') + ''; } response += `
@@ -887,7 +723,7 @@ app.put('/backend/post_upload', bodyParser.raw({ app.get('/useradmin/drive/:dongleId/:driveIdentifier/:action', runAsyncWrapper(async (req, res) => { - const account = await getAuthenticatedAccount(req); + const account = await controllers.authentication.getAuthenticatedAccount(req, res); if (account == null) { res.redirect('/useradmin?status=' + encodeURIComponent('Invalid or expired session')); return; @@ -927,7 +763,8 @@ app.put('/backend/post_upload', bodyParser.raw({ app.get('/useradmin/drive/:dongleId/:driveIdentifier', runAsyncWrapper(async (req, res) => { - const account = await getAuthenticatedAccount(req); + const account = await controllers.authentication.getAuthenticatedAccount(req, res); + if (account == null) { res.redirect('/useradmin?status=' + encodeURIComponent('Invalid or expired session')); return; @@ -966,11 +803,11 @@ app.put('/backend/post_upload', bodyParser.raw({ ` < < < Back To Device ` + device.dongle_id + `

Drive ` + drive.identifier + ` on ` + drive.dongle_id + `

- Drive Date: ` + formatDate(drive.drive_date) + `
- Upload Date: ` + formatDate(drive.created) + `
+ Drive Date: ` + controllers.helpers.formatDate(drive.drive_date) + `
+ Upload Date: ` + controllers.helpers.formatDate(drive.created) + `
Num Segments: ` + (drive.max_segment + 1) + `
Storage: ` + Math.round(drive.filesize / 1024) + ` MiB
- Duration: ` + formatDuration(drive.duration) + `
+ Duration: ` + controllers.helpers.formatDuration(drive.duration) + `
Distance: ` + Math.round(drive.distance_meters / 1000) + ` km
Is Preserved: ` + drive.is_preserved + `
Upload Complete: ` + drive.upload_complete + `
@@ -1043,23 +880,23 @@ app.put('/backend/post_upload', bodyParser.raw({ })), - app.get('/', runAsyncWrapper(async (req, res) => { + app.get('/', async (req, res) => { res.status(404); var response = '

404 Not found

' + 'Are you looking for the useradmin dashboard?'; res.send(response); - })), + }), app.get('*', runAsyncWrapper(async (req, res) => { - logger.error("HTTP.GET unhandled request: " + simpleStringify(req) + ", " + simpleStringify(res) + "") + logger.error("HTTP.GET unhandled request: " + controllers.helpers.simpleStringify(req) + ", " + controllers.helpers.simpleStringify(res) + "") res.status(400); res.send('Not Implemented'); })), app.post('*', runAsyncWrapper(async (req, res) => { - logger.error("HTTP.POST unhandled request: " + simpleStringify(req) + ", " + simpleStringify(res) + "") + logger.error("HTTP.POST unhandled request: " + controllers.helpers.simpleStringify(req) + ", " + controllers.helpers.simpleStringify(res) + "") res.status(400); res.send('Not Implemented'); })); @@ -1076,9 +913,12 @@ lockfile.lock('retropilot_server.lock', {realpath: false, stale: 30000, update: db = _models.db; models = _models.models; + const _controllers = await controllers(models, logger); + controllers = _controllers; - initializeStorage(); - updateTotalStorageUsed(); + + controllers.storage.initializeStorage(); + await controllers.storage.updateTotalStorageUsed(); var privateKey = fs.readFileSync(config.sslKey, 'utf8'); var certificate = fs.readFileSync(config.sslCrt, 'utf8');