diff --git a/middlewares/auth.middleware.js b/middlewares/auth.middleware.js index 44559bd..95ee287 100644 --- a/middlewares/auth.middleware.js +++ b/middlewares/auth.middleware.js @@ -3,7 +3,7 @@ const utils = require('../utils/utils.js') const dbtools = require('../utils/dbtools.js') module.exports = function (options) { - const { authDB, jsonResponse, exceptions } = options + const { userDB, jsonResponse, exceptions } = options const renderLogin = (res) => { if (jsonResponse) { @@ -23,6 +23,12 @@ module.exports = function (options) { return req.url === exc }) + // TODO Allowing all urls with _next in it, but not in params + if (req.url.split('?')[0].includes('_next')) { + next() + return + } + if (isException) { logger.DebugLog(`EXCEPTION: ${req.url}`, 'auth', 1) next() @@ -35,7 +41,7 @@ module.exports = function (options) { return } - const user = GetUserBySessionID(authDB, sessionID, req) + const user = GetUserBySessionID(userDB, sessionID, req) if (!user) { logger.DebugLog(`No user:${req.url}`, 'auth', 1) @@ -50,15 +56,15 @@ module.exports = function (options) { logger.DebugLog(`ID #${user.id}: ${req.url}`, 'auth', 1) - UpdateAccess(authDB, user, ip, sessionID) + UpdateAccess(userDB, user, ip, sessionID) - dbtools.Update(authDB, 'sessions', { + dbtools.Update(userDB, 'sessions', { lastAccess: utils.GetDateString() }, { id: sessionID }) - dbtools.Update(authDB, 'users', { + dbtools.Update(userDB, 'users', { lastIP: ip, lastAccess: utils.GetDateString() }, { diff --git a/modules.json b/modules.json index 55e02e9..612f6ce 100644 --- a/modules.json +++ b/modules.json @@ -30,10 +30,5 @@ "path": "./modules/stuff/stuff.js", "name": "stuff", "urls": [ "stuff.frylabs.net" ] - }, - "old": { - "path": "./modules/old/old.js", - "name": "old", - "urls": [ "qmining.tk", "www.qmining.tk" ] } } diff --git a/modules/api/api.js b/modules/api/api.js index 101f1b0..2c7a4e9 100644 --- a/modules/api/api.js +++ b/modules/api/api.js @@ -21,7 +21,6 @@ const express = require('express') const bodyParser = require('body-parser') const busboy = require('connect-busboy') -const cookieParser = require('cookie-parser') const uuidv4 = require('uuid/v4') // TODO: deprecated, but imports are not supported const fs = require('fs') const app = express() @@ -44,7 +43,6 @@ const versionFile = 'public/version' const passwordFile = 'data/dataEditorPasswords.json' const dataEditsLog = 'stats/dataEdits' const dailyDataCountFile = 'stats/dailyDataCount' -const usersDBPath = 'data/dbs/users.db' const usersDbBackupPath = 'data/dbs/backup' const maxVeteranPwGetCount = 5 @@ -52,327 +50,327 @@ const addPWPerDay = 3 // every x day a user can give a pw const maxPWCount = 2 // maximum pw give opportunities a user can have at once const daysAfterUserGetsPWs = 2 // days after user gets pw-s -if (!utils.FileExists(usersDBPath)) { - throw new Error('No user DB exists yet! please run utils/dbSetup.js first!') -} -const authDB = dbtools.GetDB(usersDBPath) +let userDB +let url -const cookieSecret = uuidv4() -app.use(cookieParser(cookieSecret)) -app.use(bodyParser.urlencoded({ - limit: '10mb', - extended: true -})) -app.use(bodyParser.json({ - limit: '10mb' -})) -app.set('view engine', 'ejs') -app.set('views', [ - './modules/api/views', - './sharedViews' -]) -app.use(auth({ - authDB: authDB, - jsonResponse: true, - exceptions: [ - '/favicon.ico', - '/login', - '/getveteranpw' - ] -})) -app.use(express.static('public')) -app.use(busboy({ - limits: { - fileSize: 50000 * 1024 * 1024 +function GetApp () { + app.use(bodyParser.urlencoded({ + limit: '10mb', + extended: true + })) + app.use(bodyParser.json({ + limit: '10mb' + })) + app.set('view engine', 'ejs') + app.set('views', [ + './modules/api/views', + './sharedViews' + ]) + app.use(auth({ + userDB: userDB, + jsonResponse: true, + exceptions: [ + '/favicon.ico', + '/login', + '/getveteranpw' + ] + })) + app.use(express.static('public')) + app.use(busboy({ + limits: { + fileSize: 50000 * 1024 * 1024 + } + })) + + var data = actions.LoadJSON(dataFile) + var version = '' + var motd = '' + + function LoadVersion () { + version = utils.ReadFile(versionFile) } -})) -var data = actions.LoadJSON(dataFile) -var version = '' -var motd = '' + function LoadMOTD () { + motd = utils.ReadFile(motdFile) + } -function LoadVersion () { - version = utils.ReadFile(versionFile) -} - -function LoadMOTD () { - motd = utils.ReadFile(motdFile) -} - -function Load () { - utils.WatchFile(motdFile, (newData) => { - logger.Log(`Motd changed: ${newData.replace(/\/n/g, '')}`) - LoadMOTD() - }) - utils.WatchFile(versionFile, (newData) => { - logger.Log(`Version changed: ${newData.replace(/\/n/g, '')}`) - LoadVersion() - }) - - LoadVersion() - LoadMOTD() -} - -Load() - -// ------------------------------------------------------------- - -app.post('/getpw', function (req, res) { - logger.LogReq(req) - - const requestingUser = req.session.user - - if (requestingUser.avaiblePWRequests <= 0) { - res.json({ - result: 'error', - msg: 'Too many passwords requested or cant request password yet, try later' + function Load () { + utils.WatchFile(motdFile, (newData) => { + logger.Log(`Motd changed: ${newData.replace(/\/n/g, '')}`) + LoadMOTD() }) - logger.Log(`User #${requestingUser.id} requested too much passwords`, logger.GetColor('cyan')) - return + utils.WatchFile(versionFile, (newData) => { + logger.Log(`Version changed: ${newData.replace(/\/n/g, '')}`) + LoadVersion() + }) + + LoadVersion() + LoadMOTD() } - dbtools.Update(authDB, 'users', { - avaiblePWRequests: requestingUser.avaiblePWRequests - 1, - pwRequestCount: requestingUser.pwRequestCount + 1 - }, { - id: requestingUser.id - }) + Load() - const pw = uuidv4() - const insertRes = dbtools.Insert(authDB, 'users', { - pw: pw, - created: utils.GetDateString() - }) + // ------------------------------------------------------------- - logger.Log(`User #${requestingUser.id} creted new user #${insertRes.lastInsertRowid}`, logger.GetColor('cyan')) + app.post('/getpw', function (req, res) { + logger.LogReq(req) - res.json({ - result: 'success', - pw: pw, - remaining: requestingUser.avaiblePWRequests - 1 - }) -}) + const requestingUser = req.session.user -app.post('/getveteranpw', function (req, res) { - logger.LogReq(req) - const ip = req.headers['cf-connecting-ip'] || req.connection.remoteAddress - - const tries = dbtools.Select(authDB, 'veteranPWRequests', { - ip: ip - })[0] - - if (tries) { - if (tries.count > maxVeteranPwGetCount) { + if (requestingUser.avaiblePWRequests <= 0) { res.json({ result: 'error', - msg: 'Too many tries' + msg: 'Too many passwords requested or cant request password yet, try later' }) - logger.Log(`Too many veteran PW requests from ${ip}!`, logger.GetColor('cyan')) + logger.Log(`User #${requestingUser.id} requested too much passwords`, logger.GetColor('cyan')) return + } + + dbtools.Update(userDB, 'users', { + avaiblePWRequests: requestingUser.avaiblePWRequests - 1, + pwRequestCount: requestingUser.pwRequestCount + 1 + }, { + id: requestingUser.id + }) + + const pw = uuidv4() + const insertRes = dbtools.Insert(userDB, 'users', { + pw: pw, + created: utils.GetDateString() + }) + + logger.Log(`User #${requestingUser.id} creted new user #${insertRes.lastInsertRowid}`, logger.GetColor('cyan')) + + res.json({ + result: 'success', + pw: pw, + remaining: requestingUser.avaiblePWRequests - 1 + }) + }) + + app.post('/getveteranpw', function (req, res) { + logger.LogReq(req) + const ip = req.headers['cf-connecting-ip'] || req.connection.remoteAddress + + const tries = dbtools.Select(userDB, 'veteranPWRequests', { + ip: ip + })[0] + + if (tries) { + if (tries.count > maxVeteranPwGetCount) { + res.json({ + result: 'error', + msg: 'Too many tries' + }) + logger.Log(`Too many veteran PW requests from ${ip}!`, logger.GetColor('cyan')) + return + } else { + dbtools.Update(userDB, 'veteranPWRequests', { + count: tries.count + 1, + lastDate: utils.GetDateString() + }, { + id: tries.id + }) + } } else { - dbtools.Update(authDB, 'veteranPWRequests', { - count: tries.count + 1, + dbtools.Insert(userDB, 'veteranPWRequests', { + ip: ip, lastDate: utils.GetDateString() - }, { - id: tries.id }) } - } else { - dbtools.Insert(authDB, 'veteranPWRequests', { - ip: ip, - lastDate: utils.GetDateString() - }) - } - const oldUserID = req.body.cid - if (!oldUserID) { - res.json({ - result: 'error', - msg: 'No CID recieved' - }) - logger.Log(`No client ID recieved`, logger.GetColor('cyan')) - return - } + const oldUserID = req.body.cid + if (!oldUserID) { + res.json({ + result: 'error', + msg: 'No CID recieved' + }) + logger.Log(`No client ID recieved`, logger.GetColor('cyan')) + return + } - const user = dbtools.Select(authDB, 'users', { - oldCID: oldUserID - })[0] + const user = dbtools.Select(userDB, 'users', { + oldCID: oldUserID + })[0] - if (user) { - if (user.pwGotFromCID === 0) { - logger.Log(`Sent password to veteran user #${user.id}`, logger.GetColor('cyan')) - dbtools.Update(authDB, 'users', { - pwGotFromCID: 1 + if (user) { + if (user.pwGotFromCID === 0) { + logger.Log(`Sent password to veteran user #${user.id}`, logger.GetColor('cyan')) + dbtools.Update(userDB, 'users', { + pwGotFromCID: 1 + }, { + id: user.id + }) + + res.json({ + result: 'success', + pw: user.pw + }) + } else { + logger.Log(`Veteran user #${user.id} already requested password`, logger.GetColor('cyan')) + res.json({ + result: 'error', + msg: 'Password already requested once' + }) + } + } else { + logger.Log(`Invalid password request with CID: ${oldUserID}`, logger.GetColor('cyan')) + res.json({ + result: 'error', + msg: 'no such CID' + }) + } + }) + + app.post('/login', (req, res) => { + logger.LogReq(req) + const pw = req.body.pw + const ip = req.headers['cf-connecting-ip'] || req.connection.remoteAddress + const user = dbtools.Select(userDB, 'users', { + pw: pw + })[0] + + if (user) { + const sessionID = uuidv4() + + // FIXME: Users now can only log in in one session, this might be too strict. + const existingSessions = dbtools.Select(userDB, 'sessions', { + userID: user.id + }) + + if (existingSessions.length > 0) { + logger.Log(`Multiple sessions ( ${existingSessions.length} ) for #${user.id}, deleting olds`, logger.GetColor('cyan')) + existingSessions.forEach((sess) => { + dbtools.Delete(userDB, 'sessions', { + id: sess.id + }) + }) + } + + dbtools.Update(userDB, 'users', { + loginCount: user.loginCount + 1, + lastIP: ip, + lastLogin: utils.GetDateString() }, { id: user.id }) + dbtools.Insert(userDB, 'sessions', { + id: sessionID, + ip: ip, + userID: user.id, + createDate: utils.GetDateString() + }) + + // TODO: cookie age + res.cookie('sessionID', sessionID, { + domain: '.frylabs.net', // TODO: use url. url: "https://api.frylabs.net" + sameSite: 'none' + }) + res.json({ result: 'success', - pw: user.pw + sessionID: sessionID }) + + logger.Log(`Successfull login with user ID: #${user.id}`, logger.GetColor('cyan')) } else { - logger.Log(`Veteran user #${user.id} already requested password`, logger.GetColor('cyan')) + logger.Log(`Login attempt with invalid pw: ${pw}`, logger.GetColor('cyan')) res.json({ - result: 'error', - msg: 'Password already requested once' + msg: 'invalid pw' }) } - } else { - logger.Log(`Invalid password request with CID: ${oldUserID}`, logger.GetColor('cyan')) - res.json({ - result: 'error', - msg: 'no such CID' - }) - } -}) - -app.post('/login', (req, res) => { - logger.LogReq(req) - const pw = req.body.pw - const ip = req.headers['cf-connecting-ip'] || req.connection.remoteAddress - const user = dbtools.Select(authDB, 'users', { - pw: pw - })[0] - - if (user) { - const sessionID = uuidv4() - - // FIXME: Users now can only log in in one session, this might be too strict. - const existingSessions = dbtools.Select(authDB, 'sessions', { - userID: user.id - }) - - if (existingSessions.length > 0) { - logger.Log(`Multiple sessions ( ${existingSessions.length} ) for #${user.id}, deleting olds`, logger.GetColor('cyan')) - existingSessions.forEach((sess) => { - dbtools.Delete(authDB, 'sessions', { - id: sess.id - }) - }) - } - - dbtools.Update(authDB, 'users', { - loginCount: user.loginCount + 1, - lastIP: ip, - lastLogin: utils.GetDateString() - }, { - id: user.id - }) - - dbtools.Insert(authDB, 'sessions', { - id: sessionID, - ip: ip, - userID: user.id, - createDate: utils.GetDateString() - }) - - // TODO: cookie age - res.cookie('sessionID', sessionID) - - res.json({ - result: 'success', - sessionID: sessionID - }) - - logger.Log(`Successfull login with user ID: #${user.id}`, logger.GetColor('cyan')) - } else { - logger.Log(`Login attempt with invalid pw: ${pw}`, logger.GetColor('cyan')) - res.json({ - msg: 'invalid pw' - }) - } -}) - -app.post('/logout', (req, res) => { - logger.LogReq(req) - const sessionID = req.cookies.sessionID - - // removing session from db - dbtools.Delete(authDB, 'sessions', { - id: sessionID }) - // TODO: remove old sessions every once in a while - res.clearCookie('sessionID').json({ - result: 'success' + + app.post('/logout', (req, res) => { + logger.LogReq(req) + const sessionID = req.cookies.sessionID + + // removing session from db + dbtools.Delete(userDB, 'sessions', { + id: sessionID + }) + // TODO: remove old sessions every once in a while + res.clearCookie('sessionID').json({ + result: 'success' + }) }) -}) -// -------------------------------------------------------------- + // -------------------------------------------------------------- -app.get('/', function (req, res) { - logger.LogReq(req) - res.redirect('https://www.youtube.com/watch?v=ieqGJgqiXFk') -}) + app.get('/', function (req, res) { + logger.LogReq(req) + res.redirect('https://www.youtube.com/watch?v=ieqGJgqiXFk') + }) -app.post('/postfeedbackfile', function (req, res) { - UploadFile(req, res, uloadFiles, (fn) => { + app.post('/postfeedbackfile', function (req, res) { + UploadFile(req, res, uloadFiles, (fn) => { + res.json({ success: true }) + }) + + logger.LogReq(req) + logger.Log('New feedback file', logger.GetColor('bluebg'), true) + }) + + app.post('/postfeedback', function (req, res) { + logger.LogReq(req) + logger.Log('New feedback message', logger.GetColor('bluebg'), true) + utils.AppendToFile(utils.GetDateString() + ':\n' + JSON.stringify(req.body), msgFile) res.json({ success: true }) }) - logger.LogReq(req) - logger.Log('New feedback file', logger.GetColor('bluebg'), true) -}) + function UploadFile (req, res, path, next) { + try { + var fstream + req.pipe(req.busboy) + req.busboy.on('file', function (fieldname, file, filename) { + logger.Log('Uploading: ' + filename, logger.GetColor('blue')) -app.post('/postfeedback', function (req, res) { - logger.LogReq(req) - logger.Log('New feedback message', logger.GetColor('bluebg'), true) - utils.AppendToFile(utils.GetDateString() + ':\n' + JSON.stringify(req.body), msgFile) - res.json({ success: true }) -}) + utils.CreatePath(path, true) + let d = new Date() + let fn = d.getHours() + '' + d.getMinutes() + '' + d.getSeconds() + '_' + filename -function UploadFile (req, res, path, next) { - try { - var fstream - req.pipe(req.busboy) - req.busboy.on('file', function (fieldname, file, filename) { - logger.Log('Uploading: ' + filename, logger.GetColor('blue')) - - utils.CreatePath(path, true) - let d = new Date() - let fn = d.getHours() + '' + d.getMinutes() + '' + d.getSeconds() + '_' + filename - - fstream = fs.createWriteStream(path + '/' + fn) - file.pipe(fstream) - fstream.on('close', function () { - logger.Log('Upload Finished of ' + path + '/' + fn, logger.GetColor('blue')) - next(fn) + fstream = fs.createWriteStream(path + '/' + fn) + file.pipe(fstream) + fstream.on('close', function () { + logger.Log('Upload Finished of ' + path + '/' + fn, logger.GetColor('blue')) + next(fn) + }) + fstream.on('error', function (err) { + console.log(err) + res.end('something bad happened :s') + }) }) - fstream.on('error', function (err) { - console.log(err) - res.end('something bad happened :s') - }) - }) - } catch (e) { - logger.Log(`Unable to upload file!`, logger.GetColor('redbg')) - console.log(e) + } catch (e) { + logger.Log(`Unable to upload file!`, logger.GetColor('redbg')) + console.log(e) + } } -} -app.route('/fosuploader').post(function (req, res, next) { - UploadFile(req, res, uloadFiles, (fn) => { - res.redirect('/f/' + fn) + app.route('/fosuploader').post(function (req, res, next) { + UploadFile(req, res, uloadFiles, (fn) => { + res.redirect('/f/' + fn) + }) }) -}) -app.route('/badtestsender').post(function (req, res, next) { - UploadFile(req, res, recivedFiles, (fn) => { - res.redirect('back') + app.route('/badtestsender').post(function (req, res, next) { + UploadFile(req, res, recivedFiles, (fn) => { + res.redirect('back') + }) + logger.LogReq(req) }) - logger.LogReq(req) -}) -app.get('/allqr.txt', function (req, res) { - res.set('Content-Type', 'text/plain') - res.send(data.toString()) - res.end() - logger.LogReq(req) -}) + app.get('/allqr.txt', function (req, res) { + res.set('Content-Type', 'text/plain') + res.send(data.toString()) + res.end() + logger.LogReq(req) + }) -// ------------------------------------------------------------------------------------------- -// API + // ------------------------------------------------------------------------------------------- + // API -app.post('/uploaddata', (req, res) => { + app.post('/uploaddata', (req, res) => { // body: JSON.stringify({ // newData: data, // count: getCount(data), @@ -381,238 +379,244 @@ app.post('/uploaddata', (req, res) => { // editedQuestions: editedQuestions // }) - const { count, initialCount, editedQuestions, password, newData } = req.body - const respStatuses = { - invalidPass: 'invalidPass', - ok: 'ok', - error: 'error' - } - - logger.LogReq(req) - - try { - // finding user - const pwds = JSON.parse(utils.ReadFile(passwordFile)) - let user = Object.keys(pwds).find((key) => { - const u = pwds[key] - return u.password === password - }) - user = pwds[user] - - // logging and stuff - logger.Log(`Data upload`, logger.GetColor('bluebg')) - logger.Log(`PWD: ${password}`, logger.GetColor('bluebg')) - // returning if user password is not ok - if (!user) { - logger.Log(`Data upload: invalid password ${password}`, logger.GetColor('red')) - utils.AppendToFile(utils.GetDateString() + '\n' + password + '(FAILED PASSWORD)\n' + JSON.stringify(editedQuestions) + '\n\n', dataEditsLog) - res.json({ status: respStatuses.invalidPass }) - return + const { count, initialCount, editedQuestions, password, newData } = req.body + const respStatuses = { + invalidPass: 'invalidPass', + ok: 'ok', + error: 'error' } - logger.Log(`Password accepted for ${user.name}`, logger.GetColor('bluebg')) - logger.Log(`Old Subjects/Questions: ${initialCount.subjectCount} / ${initialCount.questionCount} | New: ${count.subjectCount} / ${count.questionCount} | Edited question count: ${Object.keys(editedQuestions).length}`, logger.GetColor('bluebg')) - // saving detailed editedCount - utils.AppendToFile(utils.GetDateString() + '\n' + JSON.stringify(user) + '\n' + JSON.stringify(editedQuestions) + '\n\n', dataEditsLog) + logger.LogReq(req) - // making backup - utils.CopyFile('./' + dataFile, `./public/backs/data_before_${user.name}_${utils.GetDateString().replace(/ /g, '_')}`) - logger.Log('Backup made') - // writing data - utils.WriteFile(JSON.stringify(newData), dataFile) - logger.Log('New data file written') - // reloading data file - data = actions.LoadJSON(dataFile) - // data = newData - logger.Log('Data set to newData') - - res.json({ - status: respStatuses.ok, - user: user.name - }) - logger.Log('Data updating done!', logger.GetColor('bluebg')) - } catch (e) { - logger.Log(`Data upload error! `, logger.GetColor('redbg')) - console.error(e) - res.json({ status: respStatuses.error, msg: e.message }) - } -}) - -app.post('/isAdding', function (req, res) { - logger.LogReq(req) - - // automatically saves to dataFile every n write - // FIXME: req.body.datatoadd is for backwards compatibility, remove this sometime in the future - let result = actions.ProcessIncomingRequest( - req.body.datatoadd || req.body, - data, - { motd, version } - ) - - res.json({ - success: result !== -1, - newQuestions: result - }) -}) - -app.get('/ask', function (req, res) { - if (Object.keys(req.query).length === 0) { - logger.DebugLog(`No query params`, 'ask', 1) - res.json({ - message: `ask something! ?q=[question]&subj=[subject]&data=[question data]. 'subj' is optimal for faster result`, - result: [], - recievedData: JSON.stringify(req.query), - success: false - }) - } else { - if (req.query.q && req.query.data) { - let subj = req.query.subj || '' - let question = req.query.q - let recData = {} - try { - recData = JSON.parse(req.query.data) - } catch (e) { - logger.Log(`Unable to parse recieved question data! '${req.query.data}'`, logger.GetColor('redbg')) - } - let r = data.Search(question, subj, recData) - - res.json({ - result: r, - success: true + try { + // finding user + const pwds = JSON.parse(utils.ReadFile(passwordFile)) + let user = Object.keys(pwds).find((key) => { + const u = pwds[key] + return u.password === password }) - logger.DebugLog(`Question result length: ${r.length}`, 'ask', 1) - logger.DebugLog(r, 'ask', 2) - } else { - logger.DebugLog(`Invalid question`, 'ask', 1) + user = pwds[user] + + // logging and stuff + logger.Log(`Data upload`, logger.GetColor('bluebg')) + logger.Log(`PWD: ${password}`, logger.GetColor('bluebg')) + // returning if user password is not ok + if (!user) { + logger.Log(`Data upload: invalid password ${password}`, logger.GetColor('red')) + utils.AppendToFile(utils.GetDateString() + '\n' + password + '(FAILED PASSWORD)\n' + JSON.stringify(editedQuestions) + '\n\n', dataEditsLog) + res.json({ status: respStatuses.invalidPass }) + return + } + + logger.Log(`Password accepted for ${user.name}`, logger.GetColor('bluebg')) + logger.Log(`Old Subjects/Questions: ${initialCount.subjectCount} / ${initialCount.questionCount} | New: ${count.subjectCount} / ${count.questionCount} | Edited question count: ${Object.keys(editedQuestions).length}`, logger.GetColor('bluebg')) + // saving detailed editedCount + utils.AppendToFile(utils.GetDateString() + '\n' + JSON.stringify(user) + '\n' + JSON.stringify(editedQuestions) + '\n\n', dataEditsLog) + + // making backup + utils.CopyFile('./' + dataFile, `./public/backs/data_before_${user.name}_${utils.GetDateString().replace(/ /g, '_')}`) + logger.Log('Backup made') + // writing data + utils.WriteFile(JSON.stringify(newData), dataFile) + logger.Log('New data file written') + // reloading data file + data = actions.LoadJSON(dataFile) + // data = newData + logger.Log('Data set to newData') + res.json({ - message: `Invalid question :(`, + status: respStatuses.ok, + user: user.name + }) + logger.Log('Data updating done!', logger.GetColor('bluebg')) + } catch (e) { + logger.Log(`Data upload error! `, logger.GetColor('redbg')) + console.error(e) + res.json({ status: respStatuses.error, msg: e.message }) + } + }) + + app.post('/isAdding', function (req, res) { + logger.LogReq(req) + + // automatically saves to dataFile every n write + // FIXME: req.body.datatoadd is for backwards compatibility, remove this sometime in the future + let result = actions.ProcessIncomingRequest( + req.body.datatoadd || req.body, + data, + { motd, version } + ) + + res.json({ + success: result !== -1, + newQuestions: result + }) + }) + + app.get('/ask', function (req, res) { + if (Object.keys(req.query).length === 0) { + logger.DebugLog(`No query params`, 'ask', 1) + res.json({ + message: `ask something! ?q=[question]&subj=[subject]&data=[question data]. 'subj' is optimal for faster result`, result: [], recievedData: JSON.stringify(req.query), success: false }) - } - } -}) + } else { + if (req.query.q && req.query.data) { + let subj = req.query.subj || '' + let question = req.query.q + let recData = {} + try { + recData = JSON.parse(req.query.data) + } catch (e) { + logger.Log(`Unable to parse recieved question data! '${req.query.data}'`, logger.GetColor('redbg')) + } + let r = data.Search(question, subj, recData) -function getSimplreRes () { - return { - subjects: data.length, - questions: data.Subjects.reduce((acc, subj) => { - return acc + subj.length - }, 0) - } -} -function getDetailedRes () { - return data.Subjects.map((subj) => { + res.json({ + result: r, + success: true + }) + logger.DebugLog(`Question result length: ${r.length}`, 'ask', 1) + logger.DebugLog(r, 'ask', 2) + } else { + logger.DebugLog(`Invalid question`, 'ask', 1) + res.json({ + message: `Invalid question :(`, + result: [], + recievedData: JSON.stringify(req.query), + success: false + }) + } + } + }) + + function getSimplreRes () { return { - name: subj.Name, - count: subj.length + subjects: data.length, + questions: data.Subjects.reduce((acc, subj) => { + return acc + subj.length + }, 0) } - }) -} - -app.get('/datacount', function (req, res) { - logger.LogReq(req) - if (req.query.detailed === 'all') { - res.json({ - detailed: getDetailedRes(), - simple: getSimplreRes() + } + function getDetailedRes () { + return data.Subjects.map((subj) => { + return { + name: subj.Name, + count: subj.length + } }) - } else if (req.query.detailed) { - res.json(getDetailedRes()) - } else { - res.json(getSimplreRes()) - } -}) - -app.get('/infos', function (req, res) { - let result = { - result: 'success' - } - if (req.query.subjinfo) { - result.subjinfo = getSimplreRes() - } - if (req.query.version) { - result.version = version - } - if (req.query.motd) { - result.motd = motd - } - res.json(result) -}) - -// ------------------------------------------------------------------------------------------- - -app.get('*', function (req, res) { - res.status(404).render('404') -}) - -app.post('*', function (req, res) { - res.status(404).render('404') -}) - -function ExportDailyDataCount () { - logger.Log('Saving daily data count ...') - utils.AppendToFile(JSON.stringify({ - date: utils.GetDateString(), - subjectCount: data.Subjects.length, - questionCOunt: data.Subjects.reduce((acc, subj) => { - return acc + subj.Questions.length - }, 0), - userCount: dbtools.TableInfo(authDB, 'users').dataCount - }), dailyDataCountFile) -} - -function BackupDB () { - logger.Log('Backing up auth DB ...') - utils.CreatePath(usersDbBackupPath, true) - authDB.backup(`${usersDbBackupPath}/users.${utils.GetDateString().replace(/ /g, '_')}.db`) - .then(() => { - logger.Log('Auth DB backup complete!') - }) - .catch((err) => { - logger.Log('Auth DB backup failed!', logger.GetColor('redbg')) - console.error(err) - }) -} - -function IncrementAvaiblePWs () { - const users = dbtools.SelectAll(authDB, 'users') - const today = new Date() - const getDayDiff = (dateString) => { - let msdiff = today - new Date(dateString) - return Math.floor(msdiff / (1000 * 3600 * 24)) } - users.forEach((u) => { - if (u.avaiblePWRequests >= maxPWCount) { - return - } - - const dayDiff = getDayDiff(u.created) - if (dayDiff < daysAfterUserGetsPWs) { - return - } - - if (dayDiff % addPWPerDay === 0) { - dbtools.Update(authDB, 'users', { - avaiblePWRequests: u.avaiblePWRequests + 1 - }, { - id: u.id + app.get('/datacount', function (req, res) { + logger.LogReq(req) + if (req.query.detailed === 'all') { + res.json({ + detailed: getDetailedRes(), + simple: getSimplreRes() }) + } else if (req.query.detailed) { + res.json(getDetailedRes()) + } else { + res.json(getSimplreRes()) } }) + + app.get('/infos', function (req, res) { + let result = { + result: 'success' + } + if (req.query.subjinfo) { + result.subjinfo = getSimplreRes() + } + if (req.query.version) { + result.version = version + } + if (req.query.motd) { + result.motd = motd + } + res.json(result) + }) + + // ------------------------------------------------------------------------------------------- + + app.get('*', function (req, res) { + res.status(404).render('404') + }) + + app.post('*', function (req, res) { + res.status(404).render('404') + }) + + function ExportDailyDataCount () { + logger.Log('Saving daily data count ...') + utils.AppendToFile(JSON.stringify({ + date: utils.GetDateString(), + subjectCount: data.Subjects.length, + questionCOunt: data.Subjects.reduce((acc, subj) => { + return acc + subj.Questions.length + }, 0), + userCount: dbtools.TableInfo(userDB, 'users').dataCount + }), dailyDataCountFile) + } + + function BackupDB () { + logger.Log('Backing up auth DB ...') + utils.CreatePath(usersDbBackupPath, true) + userDB.backup(`${usersDbBackupPath}/users.${utils.GetDateString().replace(/ /g, '_')}.db`) + .then(() => { + logger.Log('Auth DB backup complete!') + }) + .catch((err) => { + logger.Log('Auth DB backup failed!', logger.GetColor('redbg')) + console.error(err) + }) + } + + function IncrementAvaiblePWs () { + const users = dbtools.SelectAll(userDB, 'users') + const today = new Date() + const getDayDiff = (dateString) => { + let msdiff = today - new Date(dateString) + return Math.floor(msdiff / (1000 * 3600 * 24)) + } + + users.forEach((u) => { + if (u.avaiblePWRequests >= maxPWCount) { + return + } + + const dayDiff = getDayDiff(u.created) + if (dayDiff < daysAfterUserGetsPWs) { + return + } + + if (dayDiff % addPWPerDay === 0) { + dbtools.Update(userDB, 'users', { + avaiblePWRequests: u.avaiblePWRequests + 1 + }, { + id: u.id + }) + } + }) + } + + function DailyActions () { + ExportDailyDataCount() + BackupDB() + IncrementAvaiblePWs() + } + + return { + DailyActions: DailyActions, + app: app + } } -exports.app = app -exports.cleanup = () => { - logger.Log('Closing Auth DB') - authDB.close() +exports.name = 'API' +exports.getApp = GetApp +exports.setup = (data) => { + userDB = data.userDB + url = data.url } -exports.dailyAction = () => { - ExportDailyDataCount() - BackupDB() - IncrementAvaiblePWs() -} - -logger.Log('API module started', logger.GetColor('yellow')) diff --git a/modules/dataEditor/dataEditor.js b/modules/dataEditor/dataEditor.js index a3adc7a..575c661 100644 --- a/modules/dataEditor/dataEditor.js +++ b/modules/dataEditor/dataEditor.js @@ -26,63 +26,68 @@ const app = express() const utils = require('../../utils/utils.js') const logger = require('../../utils/logger.js') -app.set('view engine', 'ejs') -app.set('views', [ - './modules/dataEditor/views', - './sharedViews' -]) -app.use(express.static('modules/dataEditor/public')) -app.use(express.static('public')) -app.use(busboy({ - limits: { - fileSize: 10000 * 1024 * 1024 - } -})) -app.use(bodyParser.json()) -app.use(bodyParser.urlencoded({ - limit: '5mb', - extended: true -})) -app.use(bodyParser.json({ - limit: '5mb' -})) - -// -------------------------------------------------------------- - -function AddHtmlRoutes (files) { - const routes = files.reduce((acc, f) => { - if (f.includes('html')) { - acc.push(f.split('.')[0]) - return acc +function GetApp () { + app.set('view engine', 'ejs') + app.set('views', [ + './modules/dataEditor/views', + './sharedViews' + ]) + app.use(express.static('modules/dataEditor/public')) + app.use(express.static('public')) + app.use(busboy({ + limits: { + fileSize: 10000 * 1024 * 1024 } - return acc - }, []) + })) + app.use(bodyParser.json()) + app.use(bodyParser.urlencoded({ + limit: '5mb', + extended: true + })) + app.use(bodyParser.json({ + limit: '5mb' + })) - routes.forEach((route) => { - logger.DebugLog(`Added route /${route}`, 'DataEditor routes', 1) - app.get(`/${route}`, function (req, res) { - logger.LogReq(req) - res.redirect(`${route}.html`) + // -------------------------------------------------------------- + + function AddHtmlRoutes (files) { + const routes = files.reduce((acc, f) => { + if (f.includes('html')) { + acc.push(f.split('.')[0]) + return acc + } + return acc + }, []) + + routes.forEach((route) => { + logger.DebugLog(`Added route /${route}`, 'DataEditor routes', 1) + app.get(`/${route}`, function (req, res) { + logger.LogReq(req) + res.redirect(`${route}.html`) + }) }) + } + AddHtmlRoutes(utils.ReadDir('modules/dataEditor/public')) + + // -------------------------------------------------------------- + + app.get('/', function (req, res) { + res.end('hai') + logger.LogReq(req) }) + + app.get('*', function (req, res) { + res.status(404).render('404') + }) + + app.post('*', function (req, res) { + res.status(404).render('404') + }) + + return { + app: app + } } -AddHtmlRoutes(utils.ReadDir('modules/dataEditor/public')) -// -------------------------------------------------------------- - -app.get('/', function (req, res) { - res.end('hai') - logger.LogReq(req) -}) - -app.get('*', function (req, res) { - res.status(404).render('404') -}) - -app.post('*', function (req, res) { - res.status(404).render('404') -}) - -exports.app = app - -logger.Log('DataEditor module started', logger.GetColor('yellow')) +exports.name = 'Data editor' +exports.getApp = GetApp diff --git a/modules/main/main.js b/modules/main/main.js index b3653d2..ebbf0b9 100644 --- a/modules/main/main.js +++ b/modules/main/main.js @@ -25,49 +25,54 @@ const bodyParser = require('body-parser') const busboy = require('connect-busboy') const app = express() -const logger = require('../../utils/logger.js') +// const logger = require('../../utils/logger.js') // const utils = require('../utils/utils.js') // const actions = require('../utils/actions.js') -app.set('view engine', 'ejs') -app.set('views', [ - './modules/main/views', - './sharedViews' -]) -app.use(express.static('public')) -app.use(busboy({ - limits: { - fileSize: 10000 * 1024 * 1024 - } -})) -app.use(bodyParser.json()) -app.use(bodyParser.urlencoded({ - limit: '5mb', - extended: true -})) -app.use(bodyParser.json({ - limit: '5mb' -})) +function GetApp () { + app.set('view engine', 'ejs') + app.set('views', [ + './modules/main/views', + './sharedViews' + ]) + app.use(express.static('public')) + app.use(busboy({ + limits: { + fileSize: 10000 * 1024 * 1024 + } + })) + app.use(bodyParser.json()) + app.use(bodyParser.urlencoded({ + limit: '5mb', + extended: true + })) + app.use(bodyParser.json({ + limit: '5mb' + })) -// -------------------------------------------------------------- + // -------------------------------------------------------------- -app.get('/', function (req, res) { - res.render('main', { - siteurl: url + app.get('/', function (req, res) { + res.render('main', { + siteurl: url + }) }) -}) -app.get('*', function (req, res) { - res.status(404).render('404') -}) + app.get('*', function (req, res) { + res.status(404).render('404') + }) -app.post('*', function (req, res) { - res.status(404).render('404') -}) + app.post('*', function (req, res) { + res.status(404).render('404') + }) -exports.app = app + return { + app: app + } +} + +exports.name = 'Main' +exports.getApp = GetApp exports.setup = (x) => { url = x.url } - -logger.Log('Main module started', logger.GetColor('yellow')) diff --git a/modules/old/old.js b/modules/old/old.js deleted file mode 100755 index 759748f..0000000 --- a/modules/old/old.js +++ /dev/null @@ -1,46 +0,0 @@ -/* ---------------------------------------------------------------------------- - - Question Server - GitLab: - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - - ------------------------------------------------------------------------- */ - -let url = '' -const express = require('express') -const app = express() - -const logger = require('../../utils/logger.js') - -// -------------------------------------------------------------- - -app.get('/', function (req, res) { - res.redirect(url + req.url) -}) - -app.get('*', function (req, res) { - res.redirect(url + req.url) -}) - -app.post('*', function (req, res) { - res.redirect(url + req.url) -}) - -exports.app = app -exports.setup = (x) => { - url = x.url -} - -logger.Log('Old module started', logger.GetColor('yellow')) diff --git a/modules/qmining/qmining.js b/modules/qmining/qmining.js index 2f8d558..ba18266 100644 --- a/modules/qmining/qmining.js +++ b/modules/qmining/qmining.js @@ -23,154 +23,170 @@ const bodyParser = require('body-parser') const busboy = require('connect-busboy') const app = express() -const reqlogger = require('../../middlewares/reqlogger.middleware.js') const utils = require('../../utils/utils.js') const logger = require('../../utils/logger.js') +const auth = require('../../middlewares/auth.middleware.js') let donateURL = '' +let userDB + try { donateURL = utils.ReadFile('./data/donateURL') } catch (e) { logger.Log('Couldnt read donate URL file!', logger.GetColor('red')) } -app.use(bodyParser.urlencoded({ - limit: '5mb', - extended: true -})) -app.use(bodyParser.json({ - limit: '5mb' -})) -app.set('view engine', 'ejs') -app.set('views', [ - './modules/qmining/views', - './sharedViews' -]) -app.use(reqlogger()) -app.use(express.static('modules/qmining/public')) -app.use(express.static('public')) -app.use(busboy({ - limits: { - fileSize: 10000 * 1024 * 1024 - } -})) - -// -------------------------------------------------------------- -// REDIRECTS -// -------------------------------------------------------------- - -// to be backwards compatible -app.get('/ask', function (req, res) { - logger.DebugLog(`Qmining module ask redirect`, 'ask', 1) - res.redirect(`http://api.frylabs.net/ask?q=${req.query.q}&subj=${req.query.subj}&data=${req.query.data}`) -}) - -const simpleRedirects = [ - { - from: '/dataeditor', - to: 'https://dataeditor.frylabs.net' - }, - { - from: '/install', - to: 'https://greasyfork.org/en/scripts/38999-moodle-elearning-kmooc-test-help' - }, - { - from: '/servergit', - to: 'https://gitlab.com/MrFry/mrfrys-node-server' - }, - { - from: '/scriptgit', - to: 'https://gitlab.com/MrFry/moodle-test-userscript' - }, - { - from: '/qminingSite', - to: 'https://gitlab.com/MrFry/qmining-page' - }, - { - from: '/classesgit', - to: 'https://gitlab.com/MrFry/question-classes' - }, - { - from: '/menuClick', - to: '/' - }, - { - from: '/lred', - to: '/allQuestions.html' - }, - { - from: '/donate', - to: donateURL - }, - { // to be backwards compatible - from: '/legacy', - to: '/allQuestions.html' - }, - { - from: '/allqr', - to: 'http://api.frylabs.net/allqr.txt' - }, - { - from: '/allqr.txt', - to: 'http://api.frylabs.net/allqr.txt' - }, - { - from: '/infos', - to: 'http://api.frylabs.net/infos?version=true&motd=true&subjinfo=true', - nolog: true - }, - { - from: '/irc', - to: 'https://kiwiirc.com/nextclient/irc.sub.fm/#qmining' - } -] - -simpleRedirects.forEach((redirect) => { - app.get(redirect.from, function (req, res) { - if (!redirect.nolog) { - logger.LogReq(req) +function GetApp () { + app.use(bodyParser.urlencoded({ + limit: '5mb', + extended: true + })) + app.use(bodyParser.json({ + limit: '5mb' + })) + app.set('view engine', 'ejs') + app.set('views', [ + './modules/qmining/views', + './sharedViews' + ]) + app.use(auth({ + userDB: userDB, + jsonResponse: false, + exceptions: [ + '/favicon.ico' + ] + })) + app.use(express.static('modules/qmining/public')) + app.use(express.static('public')) + app.use(busboy({ + limits: { + fileSize: 10000 * 1024 * 1024 } - logger.DebugLog(`Qmining module ${redirect.from} redirect`, 'infos', 1) - res.redirect(`${redirect.to}`) + })) + + // -------------------------------------------------------------- + // REDIRECTS + // -------------------------------------------------------------- + + // to be backwards compatible + app.get('/ask', function (req, res) { + logger.DebugLog(`Qmining module ask redirect`, 'ask', 1) + res.redirect(`http://api.frylabs.net/ask?q=${req.query.q}&subj=${req.query.subj}&data=${req.query.data}`) }) -}) -// -------------------------------------------------------------- - -function AddHtmlRoutes (files) { - const routes = files.reduce((acc, f) => { - if (f.includes('html')) { - acc.push(f.split('.')[0]) - return acc + const simpleRedirects = [ + { + from: '/dataeditor', + to: 'https://dataeditor.frylabs.net' + }, + { + from: '/install', + to: 'https://greasyfork.org/en/scripts/38999-moodle-elearning-kmooc-test-help' + }, + { + from: '/servergit', + to: 'https://gitlab.com/MrFry/mrfrys-node-server' + }, + { + from: '/scriptgit', + to: 'https://gitlab.com/MrFry/moodle-test-userscript' + }, + { + from: '/qminingSite', + to: 'https://gitlab.com/MrFry/qmining-page' + }, + { + from: '/classesgit', + to: 'https://gitlab.com/MrFry/question-classes' + }, + { + from: '/menuClick', + to: '/' + }, + { + from: '/lred', + to: '/allQuestions.html' + }, + { + from: '/donate', + to: donateURL + }, + { // to be backwards compatible + from: '/legacy', + to: '/allQuestions.html' + }, + { + from: '/allqr', + to: 'http://api.frylabs.net/allqr.txt' + }, + { + from: '/allqr.txt', + to: 'http://api.frylabs.net/allqr.txt' + }, + { + from: '/infos', + to: 'http://api.frylabs.net/infos?version=true&motd=true&subjinfo=true', + nolog: true + }, + { + from: '/irc', + to: 'https://kiwiirc.com/nextclient/irc.sub.fm/#qmining' } - return acc - }, []) + ] - routes.forEach((route) => { - logger.DebugLog(`Added route /${route}`, 'Qmining routes', 1) - app.get(`/${route}`, function (req, res) { - logger.LogReq(req) - res.redirect(`${route}.html`) + simpleRedirects.forEach((redirect) => { + app.get(redirect.from, function (req, res) { + if (!redirect.nolog) { + logger.LogReq(req) + } + logger.DebugLog(`Qmining module ${redirect.from} redirect`, 'infos', 1) + res.redirect(`${redirect.to}`) }) }) + + // -------------------------------------------------------------- + + function AddHtmlRoutes (files) { + const routes = files.reduce((acc, f) => { + if (f.includes('html')) { + acc.push(f.split('.')[0]) + return acc + } + return acc + }, []) + + routes.forEach((route) => { + logger.DebugLog(`Added route /${route}`, 'Qmining routes', 1) + app.get(`/${route}`, function (req, res) { + logger.LogReq(req) + res.redirect(`${route}.html`) + }) + }) + } + AddHtmlRoutes(utils.ReadDir('modules/qmining/public')) + + // -------------------------------------------------------------- + + app.get('/', function (req, res) { + res.end('hai') + logger.LogReq(req) + }) + + app.get('*', function (req, res) { + res.status(404).render('404') + }) + + app.post('*', function (req, res) { + res.status(404).render('404') + }) + + return { + app: app + } } -AddHtmlRoutes(utils.ReadDir('modules/qmining/public')) -// -------------------------------------------------------------- - -app.get('/', function (req, res) { - res.end('hai') - logger.LogReq(req) -}) - -app.get('*', function (req, res) { - res.status(404).render('404') -}) - -app.post('*', function (req, res) { - res.status(404).render('404') -}) - -exports.app = app - -logger.Log('Qmining module started', logger.GetColor('yellow')) +exports.name = 'Qmining' +exports.getApp = GetApp +exports.setup = (data) => { + userDB = data.userDB +} diff --git a/modules/sio/sio.js b/modules/sio/sio.js index 75c7baa..2eaaab0 100644 --- a/modules/sio/sio.js +++ b/modules/sio/sio.js @@ -31,69 +31,74 @@ const utils = require('../../utils/utils.js') const uloadFiles = './public/f' -app.set('view engine', 'ejs') -app.set('views', [ - './modules/sio/views', - './sharedViews' -]) -app.use(express.static('public')) -app.use(busboy({ - limits: { - fileSize: 10000 * 1024 * 1024 - } -})) -app.use(bodyParser.json()) -app.use(bodyParser.urlencoded({ - limit: '5mb', - extended: true -})) -app.use(bodyParser.json({ - limit: '5mb' -})) +function GetApp () { + app.set('view engine', 'ejs') + app.set('views', [ + './modules/sio/views', + './sharedViews' + ]) + app.use(express.static('public')) + app.use(busboy({ + limits: { + fileSize: 10000 * 1024 * 1024 + } + })) + app.use(bodyParser.json()) + app.use(bodyParser.urlencoded({ + limit: '5mb', + extended: true + })) + app.use(bodyParser.json({ + limit: '5mb' + })) -// -------------------------------------------------------------- + // -------------------------------------------------------------- -app.get('/', function (req, res) { - res.render('uload') - res.end() -}) + app.get('/', function (req, res) { + res.render('uload') + res.end() + }) -function UploadFile (req, res, path, next) { - var fstream - req.pipe(req.busboy) - req.busboy.on('file', function (fieldname, file, filename) { - logger.Log('Uploading: ' + filename, logger.GetColor('blue')) + function UploadFile (req, res, path, next) { + var fstream + req.pipe(req.busboy) + req.busboy.on('file', function (fieldname, file, filename) { + logger.Log('Uploading: ' + filename, logger.GetColor('blue')) - utils.CreatePath(path, true) - let d = new Date() - let fn = d.getHours() + '' + d.getMinutes() + '' + d.getSeconds() + '_' + filename + utils.CreatePath(path, true) + let d = new Date() + let fn = d.getHours() + '' + d.getMinutes() + '' + d.getSeconds() + '_' + filename - fstream = fs.createWriteStream(path + '/' + fn) - file.pipe(fstream) - fstream.on('close', function () { - logger.Log('Upload Finished of ' + path + '/' + fn, logger.GetColor('blue')) - next(fn) + fstream = fs.createWriteStream(path + '/' + fn) + file.pipe(fstream) + fstream.on('close', function () { + logger.Log('Upload Finished of ' + path + '/' + fn, logger.GetColor('blue')) + next(fn) + }) + fstream.on('error', function (err) { + console.log(err) + res.end('something bad happened :s') + }) }) - fstream.on('error', function (err) { - console.log(err) - res.end('something bad happened :s') + } + + app.route('/fosuploader').post(function (req, res, next) { + UploadFile(req, res, uloadFiles, (fn) => { + res.redirect('/f/' + fn) }) }) + app.get('*', function (req, res) { + res.status(404).render('404') + }) + + app.post('*', function (req, res) { + res.status(404).render('404') + }) + + return { + app: app + } } -app.route('/fosuploader').post(function (req, res, next) { - UploadFile(req, res, uloadFiles, (fn) => { - res.redirect('/f/' + fn) - }) -}) -app.get('*', function (req, res) { - res.status(404).render('404') -}) - -app.post('*', function (req, res) { - res.status(404).render('404') -}) - -exports.app = app - -logger.Log('Sio module started', logger.GetColor('yellow')) +exports.name = 'Sio' +exports.getApp = GetApp diff --git a/modules/stuff/stuff.js b/modules/stuff/stuff.js index 129ae94..51d3555 100644 --- a/modules/stuff/stuff.js +++ b/modules/stuff/stuff.js @@ -31,183 +31,188 @@ const logger = require('../../utils/logger.js') const listedFiles = './public/files' -app.set('view engine', 'ejs') -app.set('views', [ - './modules/stuff/views', - './sharedViews' -]) -app.use(express.static('public')) -app.use(busboy({ - limits: { - fileSize: 10000 * 1024 * 1024 - } -})) -app.use(bodyParser.json()) -app.use(bodyParser.urlencoded({ - limit: '5mb', - extended: true -})) -app.use(bodyParser.json({ - limit: '5mb' -})) - -// -------------------------------------------------------------- - -// app, '/*.mp4', 'video/mp4', 'stuff/video' -function appGetFileType (app, wildcard, contentType, pageToRender) { - app.get(wildcard, function (req, res) { - let p = decodeURI(req.url) - let fp = p - if (p.includes('?')) { - fp = p.split('?') - fp.pop() - fp = fp.join('/') +function GetApp () { + app.set('view engine', 'ejs') + app.set('views', [ + './modules/stuff/views', + './sharedViews' + ]) + app.use(express.static('public')) + app.use(busboy({ + limits: { + fileSize: 10000 * 1024 * 1024 } - const fpath = './public/files' + fp - if (!fs.existsSync(fpath)) { - res.render('nofile', { - missingFile: fpath, - url - }) - return - } - if (req.query.stream || !pageToRender) { - const stat = fs.statSync(fpath) - const fileSize = stat.size - const range = req.headers.range - if (range) { - const parts = range.replace(/bytes=/, '').split('-') - const start = parseInt(parts[0], 10) - const end = parts[1] - ? parseInt(parts[1], 10) - : fileSize - 1 - const chunksize = (end - start) + 1 - const file = fs.createReadStream(fpath, { start, end }) - const head = { - 'Content-Range': `bytes ${start}-${end}/${fileSize}`, - 'Accept-Ranges': 'bytes', - 'Content-Length': chunksize, - 'Content-Type': contentType - } - res.writeHead(206, head) - file.pipe(res) - } else { - const head = { - 'Content-Length': fileSize, - 'Content-Type': contentType - } - res.writeHead(200, head) - fs.createReadStream(fpath).pipe(res) + })) + app.use(bodyParser.json()) + app.use(bodyParser.urlencoded({ + limit: '5mb', + extended: true + })) + app.use(bodyParser.json({ + limit: '5mb' + })) + + // -------------------------------------------------------------- + + // app, '/*.mp4', 'video/mp4', 'stuff/video' + function appGetFileType (app, wildcard, contentType, pageToRender) { + app.get(wildcard, function (req, res) { + let p = decodeURI(req.url) + let fp = p + if (p.includes('?')) { + fp = p.split('?') + fp.pop() + fp = fp.join('/') } - } else { - logger.LogReq(req) - let fname = fpath.split('/') - fname = fname.pop() - res.render(pageToRender, { - path: fp, - fname, - url, - contentType, - albumArt: GetAlbumArt(p) + const fpath = './public/files' + fp + if (!fs.existsSync(fpath)) { + res.render('nofile', { + missingFile: fpath, + url + }) + return + } + if (req.query.stream || !pageToRender) { + const stat = fs.statSync(fpath) + const fileSize = stat.size + const range = req.headers.range + if (range) { + const parts = range.replace(/bytes=/, '').split('-') + const start = parseInt(parts[0], 10) + const end = parts[1] + ? parseInt(parts[1], 10) + : fileSize - 1 + const chunksize = (end - start) + 1 + const file = fs.createReadStream(fpath, { start, end }) + const head = { + 'Content-Range': `bytes ${start}-${end}/${fileSize}`, + 'Accept-Ranges': 'bytes', + 'Content-Length': chunksize, + 'Content-Type': contentType + } + res.writeHead(206, head) + file.pipe(res) + } else { + const head = { + 'Content-Length': fileSize, + 'Content-Type': contentType + } + res.writeHead(200, head) + fs.createReadStream(fpath).pipe(res) + } + } else { + logger.LogReq(req) + let fname = fpath.split('/') + fname = fname.pop() + res.render(pageToRender, { + path: fp, + fname, + url, + contentType, + albumArt: GetAlbumArt(p) + }) + } + }) + } + + const fileTypes = [ + ['/*.mp4', 'video/mp4', 'video'], + ['/*.mkv', 'audio/x-matroska', 'video'], + ['/*.mp3', 'audio/mpeg', 'audio'], + ['/*.pdf', 'application/pdf'], + ['/*.zip', 'application/zip'] + ] + + function GetAlbumArt (path) { + let tmp = path.split('.') + tmp.pop() + tmp = tmp.join('.').split('/') + let last = tmp.pop() + + return tmp.join('/') + '/.' + last + '.png' + } + + fileTypes.forEach((t) => { + appGetFileType(app, t[0], t[1], t[2]) + }) + + app.get('/*', function (req, res) { + let parsedUrl = decodeURI(req.url) + let curr = listedFiles + '/' + parsedUrl.substring('/'.length, parsedUrl.length).split('?')[0] + let relPath = curr.substring('./public/files'.length, curr.length) + + if (relPath[relPath.length - 1] !== '/') { relPath += '/' } + + let t = relPath.split('/') + let prevDir = '' + for (let i = 0; i < t.length - 2; i++) { prevDir += t[i] + '/' } + + // curr = curr.replace(/\//g, "/"); + // relPath = relPath.replace(/\//g, "/"); + + logger.LogReq(req) + + try { + const stat = fs.lstatSync(curr) + if (stat.isDirectory() || stat.isSymbolicLink()) { + if (curr[curr.length - 1] !== '/') { curr += '/' } + + let f = [] + + fs.readdirSync(curr).forEach((item) => { + if (item[0] !== '.') { + let res = { name: item } + let stat = fs.statSync(curr + '/' + item) + + let fileSizeInBytes = stat['size'] + res.size = Math.round(fileSizeInBytes / 1000000) + + res.path = relPath + if (res.path[res.path.length - 1] !== '/') { res.path += '/' } + res.path += item + + res.mtime = stat['mtime'].toLocaleString() + res.isDir = stat.isDirectory() + + f.push(res) + } + }) + + res.render('folders', { + folders: f, + dirname: relPath, + prevDir, + url + }) + } else { + let fileStream = fs.createReadStream(curr) + fileStream.pipe(res) + } + } catch (e) { + res.render('nofile', { + missingFile: curr, + url }) } }) -} -const fileTypes = [ - ['/*.mp4', 'video/mp4', 'video'], - ['/*.mkv', 'audio/x-matroska', 'video'], - ['/*.mp3', 'audio/mpeg', 'audio'], - ['/*.pdf', 'application/pdf'], - ['/*.zip', 'application/zip'] -] + // ----------------------------------------------------------------------------------------------- -function GetAlbumArt (path) { - let tmp = path.split('.') - tmp.pop() - tmp = tmp.join('.').split('/') - let last = tmp.pop() + app.get('*', function (req, res) { + res.status(404).render('404') + }) - return tmp.join('/') + '/.' + last + '.png' -} + app.post('*', function (req, res) { + res.status(404).render('404') + }) -fileTypes.forEach((t) => { - appGetFileType(app, t[0], t[1], t[2]) -}) - -app.get('/*', function (req, res) { - let parsedUrl = decodeURI(req.url) - let curr = listedFiles + '/' + parsedUrl.substring('/'.length, parsedUrl.length).split('?')[0] - let relPath = curr.substring('./public/files'.length, curr.length) - - if (relPath[relPath.length - 1] !== '/') { relPath += '/' } - - let t = relPath.split('/') - let prevDir = '' - for (let i = 0; i < t.length - 2; i++) { prevDir += t[i] + '/' } - - // curr = curr.replace(/\//g, "/"); - // relPath = relPath.replace(/\//g, "/"); - - logger.LogReq(req) - - try { - const stat = fs.lstatSync(curr) - if (stat.isDirectory() || stat.isSymbolicLink()) { - if (curr[curr.length - 1] !== '/') { curr += '/' } - - let f = [] - - fs.readdirSync(curr).forEach((item) => { - if (item[0] !== '.') { - let res = { name: item } - let stat = fs.statSync(curr + '/' + item) - - let fileSizeInBytes = stat['size'] - res.size = Math.round(fileSizeInBytes / 1000000) - - res.path = relPath - if (res.path[res.path.length - 1] !== '/') { res.path += '/' } - res.path += item - - res.mtime = stat['mtime'].toLocaleString() - res.isDir = stat.isDirectory() - - f.push(res) - } - }) - - res.render('folders', { - folders: f, - dirname: relPath, - prevDir, - url - }) - } else { - let fileStream = fs.createReadStream(curr) - fileStream.pipe(res) - } - } catch (e) { - res.render('nofile', { - missingFile: curr, - url - }) + return { + app: app } -}) +} -// ----------------------------------------------------------------------------------------------- - -app.get('*', function (req, res) { - res.status(404).render('404') -}) - -app.post('*', function (req, res) { - res.status(404).render('404') -}) - -exports.app = app +exports.name = 'Stuff' +exports.getApp = GetApp exports.setup = (x) => { url = x.url } - -logger.Log('Stuff module started', logger.GetColor('yellow')) diff --git a/server.js b/server.js index 46db985..a991ae1 100755 --- a/server.js +++ b/server.js @@ -20,7 +20,7 @@ console.clear() const startHTTPS = true -const port = 8080 +const port = 80 const httpsport = 5001 const express = require('express') @@ -30,10 +30,19 @@ const utils = require('./utils/utils.js') const http = require('http') const https = require('https') const cors = require('cors') +const cookieParser = require('cookie-parser') +const uuidv4 = require('uuid/v4') // TODO: deprecated, but imports are not supported +const dbtools = require('./utils/dbtools.js') const reqlogger = require('./middlewares/reqlogger.middleware.js') const extraModulesFile = './extraModules.json' const modulesFile = './modules.json' +const usersDBPath = 'data/dbs/users.db' + +if (!utils.FileExists(usersDBPath)) { + throw new Error('No user DB exists yet! please run utils/dbSetup.js first!') +} +const userDB = dbtools.GetDB(usersDBPath) let modules = JSON.parse(utils.ReadFile(modulesFile)) @@ -70,15 +79,25 @@ function exit (reason) { x.cleanup() } catch (e) { logger.Log(`Error in ${k} cleanup! Details in STDERR`, logger.GetColor('redbg')) - console.err(e) + console.error(e) } } }) + + logger.Log('Closing Auth DB') + userDB.close() + process.exit() } const app = express() -app.use(cors()) +app.use(cors({ + credentials: true, + origin: true + // origin: [ /\.frylabs\.net$/ ] +})) +const cookieSecret = uuidv4() +app.use(cookieParser(cookieSecret)) app.use(reqlogger({ loggableKeywords: [ 'stable.user.js' @@ -92,14 +111,19 @@ Object.keys(modules).forEach(function (k, i) { let x = modules[k] try { let mod = require(x.path) + logger.Log(`Loading ${mod.name} module`, logger.GetColor('yellow')) if (mod.setup) { mod.setup({ - url: 'https://' + x.urls[0] + url: 'https://' + x.urls[0], + userDB: userDB }) } - x.app = mod.app - x.dailyAction = mod.dailyAction - x.cleanup = mod.cleanup + + const modApp = mod.getApp() + x.app = modApp.app + x.dailyAction = modApp.DailyAction + x.cleanup = modApp.cleanup + x.urls.forEach((url) => { app.use(vhost(url, x.app)) }) diff --git a/sharedViews/login.ejs b/sharedViews/login.ejs new file mode 100644 index 0000000..511af66 --- /dev/null +++ b/sharedViews/login.ejs @@ -0,0 +1,34 @@ + + + + login + + + + +
+

+ Frylabs Login +

+
+ Jelszó: +
+
+ + +
+
+ + + diff --git a/utils/dbtools.js b/utils/dbtools.js index 917952e..b745427 100644 --- a/utils/dbtools.js +++ b/utils/dbtools.js @@ -216,6 +216,9 @@ function CloseDB (db) { // ------------------------------------------------------------------------- function PrepareStatement (db, s) { + if (!db) { + throw new Error('DB is undefined in prepare statement! DB action called with undefined db') + } DebugLog(s) return db.prepare(s) }