diff options
Diffstat (limited to 'src/api')
| -rw-r--r-- | src/api/routes/albums/albumDELETE.js | 4 | ||||
| -rw-r--r-- | src/api/routes/albums/albumGET.js | 4 | ||||
| -rw-r--r-- | src/api/routes/albums/albumPOST.js | 4 | ||||
| -rw-r--r-- | src/api/routes/albums/albumZipGET.js | 8 | ||||
| -rw-r--r-- | src/api/routes/albums/albumsGET.js | 6 | ||||
| -rw-r--r-- | src/api/routes/albums/link/linkEditPOST.js | 4 | ||||
| -rw-r--r-- | src/api/routes/albums/link/linkPOST.js | 6 | ||||
| -rw-r--r-- | src/api/routes/auth/changePasswordPOST.js | 4 | ||||
| -rw-r--r-- | src/api/routes/auth/registerPOST.js | 6 | ||||
| -rw-r--r-- | src/api/routes/configGET.js | 22 | ||||
| -rw-r--r-- | src/api/routes/files/fileDELETE.js | 4 | ||||
| -rw-r--r-- | src/api/routes/files/filesGET.js | 4 | ||||
| -rw-r--r-- | src/api/routes/files/uploadPOST.js | 90 | ||||
| -rw-r--r-- | src/api/routes/verifyGET.js | 2 | ||||
| -rw-r--r-- | src/api/structures/Route.js | 24 | ||||
| -rw-r--r-- | src/api/structures/Server.js | 32 | ||||
| -rw-r--r-- | src/api/utils/Util.js | 66 |
17 files changed, 124 insertions, 166 deletions
diff --git a/src/api/routes/albums/albumDELETE.js b/src/api/routes/albums/albumDELETE.js index eefbf41..3fdf209 100644 --- a/src/api/routes/albums/albumDELETE.js +++ b/src/api/routes/albums/albumDELETE.js @@ -1,6 +1,4 @@ const Route = require('../../structures/Route'); -const config = require('../../../../config'); -const db = require('knex')(config.server.database); const Util = require('../../utils/Util'); const log = require('../../utils/Log'); @@ -9,7 +7,7 @@ class albumDELETE extends Route { super('/album/:id/:purge*?', 'delete'); } - async run(req, res, user) { + async run(req, res, db, user) { const { id, purge } = req.params; if (!id) return res.status(400).json({ message: 'Invalid album ID supplied' }); diff --git a/src/api/routes/albums/albumGET.js b/src/api/routes/albums/albumGET.js index f5e339f..59398a1 100644 --- a/src/api/routes/albums/albumGET.js +++ b/src/api/routes/albums/albumGET.js @@ -1,6 +1,4 @@ const Route = require('../../structures/Route'); -const config = require('../../../../config'); -const db = require('knex')(config.server.database); const Util = require('../../utils/Util'); class albumGET extends Route { @@ -8,7 +6,7 @@ class albumGET extends Route { super('/album/:identifier', 'get', { bypassAuth: true }); } - async run(req, res) { + async run(req, res, db) { const { identifier } = req.params; if (!identifier) return res.status(400).json({ message: 'Invalid identifier supplied' }); diff --git a/src/api/routes/albums/albumPOST.js b/src/api/routes/albums/albumPOST.js index 12b88fa..0d3a44c 100644 --- a/src/api/routes/albums/albumPOST.js +++ b/src/api/routes/albums/albumPOST.js @@ -1,6 +1,4 @@ const Route = require('../../structures/Route'); -const config = require('../../../../config'); -const db = require('knex')(config.server.database); const moment = require('moment'); class albumPOST extends Route { @@ -8,7 +6,7 @@ class albumPOST extends Route { super('/album/new', 'post'); } - async run(req, res, user) { + async run(req, res, db, user) { if (!req.body) return res.status(400).json({ message: 'No body provided' }); const { name } = req.body; if (!name) return res.status(400).json({ message: 'No name provided' }); diff --git a/src/api/routes/albums/albumZipGET.js b/src/api/routes/albums/albumZipGET.js index 7a853cd..9419654 100644 --- a/src/api/routes/albums/albumZipGET.js +++ b/src/api/routes/albums/albumZipGET.js @@ -1,6 +1,4 @@ const Route = require('../../structures/Route'); -const config = require('../../../../config'); -const db = require('knex')(config.server.database); const Util = require('../../utils/Util'); const log = require('../../utils/Log'); const path = require('path'); @@ -11,7 +9,7 @@ class albumGET extends Route { super('/album/:identifier/zip', 'get', { bypassAuth: true }); } - async run(req, res) { + async run(req, res, db) { const { identifier } = req.params; if (!identifier) return res.status(400).json({ message: 'Invalid identifier supplied' }); @@ -31,7 +29,7 @@ class albumGET extends Route { If the date when the album was zipped is greater than the album's last edit, we just send the zip to the user */ if (album.zippedAt > album.editedAt) { - const filePath = path.join(__dirname, '..', '..', '..', '..', config.uploads.uploadFolder, 'zips', `${album.userId}-${album.id}.zip`); + const filePath = path.join(__dirname, '..', '..', '..', '..', process.env.UPLOAD_FOLDER, 'zips', `${album.userId}-${album.id}.zip`); const exists = await jetpack.existsAsync(filePath); /* Make sure the file exists just in case, and if not, continue to it's generation. @@ -65,7 +63,7 @@ class albumGET extends Route { Util.createZip(filesToZip, album); await db.table('albums').where('id', link.albumId).update('zippedAt', db.fn.now()); - const filePath = path.join(__dirname, '..', '..', '..', '..', config.uploads.uploadFolder, 'zips', `${album.userId}-${album.id}.zip`); + const filePath = path.join(__dirname, '..', '..', '..', '..', process.env.UPLOAD_FOLDER, 'zips', `${album.userId}-${album.id}.zip`); const fileName = `lolisafe-${identifier}.zip`; return res.download(filePath, fileName); } catch (error) { diff --git a/src/api/routes/albums/albumsGET.js b/src/api/routes/albums/albumsGET.js index b19e03a..3be1213 100644 --- a/src/api/routes/albums/albumsGET.js +++ b/src/api/routes/albums/albumsGET.js @@ -1,6 +1,4 @@ const Route = require('../../structures/Route'); -const config = require('../../../../config'); -const db = require('knex')(config.server.database); const Util = require('../../utils/Util'); class albumsGET extends Route { @@ -8,7 +6,7 @@ class albumsGET extends Route { super('/albums/mini', 'get'); } - async run(req, res, user) { + async run(req, res, db, user) { /* Let's fetch the albums. This route will only return a small portion of the album files for displaying on the dashboard. It's probably useless @@ -72,7 +70,7 @@ class albumsDropdownGET extends Route { super('/albums/dropdown', 'get'); } - async run(req, res, user) { + async run(req, res, db, user) { const albums = await db.table('albums') .where('userId', user.id) .select('id', 'name'); diff --git a/src/api/routes/albums/link/linkEditPOST.js b/src/api/routes/albums/link/linkEditPOST.js index d9dbcac..753c496 100644 --- a/src/api/routes/albums/link/linkEditPOST.js +++ b/src/api/routes/albums/link/linkEditPOST.js @@ -1,6 +1,4 @@ const Route = require('../../../structures/Route'); -const config = require('../../../../../config'); -const db = require('knex')(config.server.database); const log = require('../../../utils/Log'); class linkEditPOST extends Route { @@ -8,7 +6,7 @@ class linkEditPOST extends Route { super('/album/link/edit', 'post'); } - async run(req, res, user) { + async run(req, res, db, user) { if (!req.body) return res.status(400).json({ message: 'No body provided' }); const { identifier, enabled, enableDownload, expiresAt } = req.body; if (!identifier) return res.status(400).json({ message: 'Invalid album identifier supplied' }); diff --git a/src/api/routes/albums/link/linkPOST.js b/src/api/routes/albums/link/linkPOST.js index 1edf891..91e1521 100644 --- a/src/api/routes/albums/link/linkPOST.js +++ b/src/api/routes/albums/link/linkPOST.js @@ -1,6 +1,4 @@ const Route = require('../../../structures/Route'); -const config = require('../../../../../config'); -const db = require('knex')(config.server.database); const Util = require('../../../utils/Util'); const log = require('../../../utils/Log'); @@ -9,7 +7,7 @@ class linkPOST extends Route { super('/album/link/new', 'post'); } - async run(req, res, user) { + async run(req, res, db, user) { if (!req.body) return res.status(400).json({ message: 'No body provided' }); const { albumId } = req.body; if (!albumId) return res.status(400).json({ message: 'No album provided' }); @@ -24,7 +22,7 @@ class linkPOST extends Route { Count the amount of links created for that album already and error out if max was reached */ const count = await db.table('links').where('albumId', albumId).count({ count: 'id' }); - if (count[0].count >= config.albums.maxLinksPerAlbum) return res.status(400).json({ message: 'Maximum links per album reached' }); + if (count[0].count >= process.env.MAX_LINKS_PER_ALBUM) return res.status(400).json({ message: 'Maximum links per album reached' }); /* Try to allocate a new identifier on the db diff --git a/src/api/routes/auth/changePasswordPOST.js b/src/api/routes/auth/changePasswordPOST.js index bd64320..d698896 100644 --- a/src/api/routes/auth/changePasswordPOST.js +++ b/src/api/routes/auth/changePasswordPOST.js @@ -1,7 +1,5 @@ const Route = require('../../structures/Route'); -const config = require('../../../../config'); const log = require('../../utils/Log'); -const db = require('knex')(config.server.database); const bcrypt = require('bcrypt'); const moment = require('moment'); @@ -10,7 +8,7 @@ class changePasswordPOST extends Route { super('/auth/password/change', 'post'); } - async run(req, res, user) { + async run(req, res, db, user) { if (!req.body) return res.status(400).json({ message: 'No body provided' }); const { password, newPassword } = req.body; if (!password || !newPassword) return res.status(401).json({ message: 'Invalid body provided' }); diff --git a/src/api/routes/auth/registerPOST.js b/src/api/routes/auth/registerPOST.js index d3532f4..762eaf2 100644 --- a/src/api/routes/auth/registerPOST.js +++ b/src/api/routes/auth/registerPOST.js @@ -1,7 +1,5 @@ const Route = require('../../structures/Route'); -const config = require('../../../../config'); const log = require('../../utils/Log'); -const db = require('knex')(config.server.database); const bcrypt = require('bcrypt'); const randomstring = require('randomstring'); const moment = require('moment'); @@ -11,8 +9,8 @@ class registerPOST extends Route { super('/auth/register', 'post', { bypassAuth: true }); } - async run(req, res) { - if (!config.enableCreateUserAccounts) return res.status(401).json({ message: 'Creation of new accounts is currently disabled' }); + async run(req, res, db) { + if (!process.env.USER_ACCOUNTS) return res.status(401).json({ message: 'Creation of new accounts is currently disabled' }); if (!req.body) return res.status(400).json({ message: 'No body provided' }); const { username, password } = req.body; if (!username || !password) return res.status(401).json({ message: 'Invalid body provided' }); diff --git a/src/api/routes/configGET.js b/src/api/routes/configGET.js deleted file mode 100644 index 4bc7e15..0000000 --- a/src/api/routes/configGET.js +++ /dev/null @@ -1,22 +0,0 @@ -const Route = require('../structures/Route'); -const config = require('../../../config'); - -class configGET extends Route { - constructor() { - super('/config', 'get', { bypassAuth: true }); - } - - run(req, res) { - return res.json({ - version: process.env.npm_package_version, - URL: config.filesServeLocatio, - baseURL: config.backendLocation, - serviceName: config.serviceName, - maxFileSize: config.uploads.uploadMaxSize, - chunkSize: config.uploads.chunkSize, - maxLinksPerAlbum: config.albums.maxLinksPerAlbum - }); - } -} - -module.exports = configGET; diff --git a/src/api/routes/files/fileDELETE.js b/src/api/routes/files/fileDELETE.js index b50e576..c659255 100644 --- a/src/api/routes/files/fileDELETE.js +++ b/src/api/routes/files/fileDELETE.js @@ -1,6 +1,4 @@ const Route = require('../../structures/Route'); -const config = require('../../../../config'); -const db = require('knex')(config.server.database); const Util = require('../../utils/Util'); const log = require('../../utils/Log'); @@ -9,7 +7,7 @@ class fileDELETE extends Route { super('/file/:id', 'delete'); } - async run(req, res, user) { + async run(req, res, db, user) { const { id } = req.params; if (!id) return res.status(400).json({ message: 'Invalid file ID supplied' }); diff --git a/src/api/routes/files/filesGET.js b/src/api/routes/files/filesGET.js index d1b6619..b41996b 100644 --- a/src/api/routes/files/filesGET.js +++ b/src/api/routes/files/filesGET.js @@ -1,6 +1,4 @@ const Route = require('../../structures/Route'); -const config = require('../../../../config'); -const db = require('knex')(config.server.database); const Util = require('../../utils/Util'); class filesGET extends Route { @@ -8,7 +6,7 @@ class filesGET extends Route { super('/files', 'get'); } - async run(req, res, user) { + async run(req, res, db, user) { /* Get all the files from the user */ diff --git a/src/api/routes/files/uploadPOST.js b/src/api/routes/files/uploadPOST.js index f217167..f83148f 100644 --- a/src/api/routes/files/uploadPOST.js +++ b/src/api/routes/files/uploadPOST.js @@ -1,8 +1,6 @@ const Route = require('../../structures/Route'); -const config = require('../../../../config'); const path = require('path'); const Util = require('../../utils/Util'); -const db = require('knex')(config.server.database); const moment = require('moment'); const log = require('../../utils/Log'); const jetpack = require('fs-jetpack'); @@ -22,13 +20,13 @@ class uploadPOST extends Route { super('/upload', 'post', { bypassAuth: true }); } - async run(req, res) { + async run(req, res, db) { const user = await Util.isAuthorized(req); - if (!user && !config.uploads.allowAnonymousUploads) return res.status(401).json({ message: 'Not authorized to use this resource' }); - return this.uploadFile(req, res, user); + if (!user && !process.env.PUBLIC_MODE) return res.status(401).json({ message: 'Not authorized to use this resource' }); + return this.uploadFile(req, res, db, user); } - async processFile(req, res, user, file) { + async processFile(req, res, db, user, file) { /* Check if the user is trying to upload to an album */ @@ -55,38 +53,37 @@ class uploadPOST extends Route { We got a chunk that is not the last part, send smoke signal that we received it. */ return res.json({ message: 'Successfully uploaded chunk' }); - } else { - /* - Seems we finally got the last part of a chunk upload - */ - const uploadsDir = path.join(__dirname, '..', '..', '..', '..', config.uploads.uploadFolder); - const chunkedFileDir = path.join(__dirname, '..', '..', '..', '..', config.uploads.uploadFolder, 'chunks', file.body.uuid); - const chunkFiles = await jetpack.findAsync(chunkedFileDir, { matching: '*' }); - const originalname = Util.getFilenameFromPath(chunkFiles[0].substring(0, chunkFiles[0].lastIndexOf('.'))); - - const tempFile = { - filename: Util.getUniqueFilename(originalname), - originalname, - size: file.body.totalfilesize - }; - - for (const chunkFile of chunkFiles) { - try { - const data = await jetpack.readAsync(chunkFile, 'buffer'); // eslint-disable-line no-await-in-loop - await jetpack.appendAsync(path.join(uploadsDir, tempFile.filename), data); // eslint-disable-line no-await-in-loop - } catch (error) { - log.error(error); - } - } - + } + /* + Seems we finally got the last part of a chunk upload + */ + const uploadsDir = path.join(__dirname, '..', '..', '..', '..', process.env.UPLOAD_FOLDER); + const chunkedFileDir = path.join(__dirname, '..', '..', '..', '..', process.env.UPLOAD_FOLDER, 'chunks', file.body.uuid); + const chunkFiles = await jetpack.findAsync(chunkedFileDir, { matching: '*' }); + const originalname = Util.getFilenameFromPath(chunkFiles[0].substring(0, chunkFiles[0].lastIndexOf('.'))); + + const tempFile = { + filename: Util.getUniqueFilename(originalname), + originalname, + size: file.body.totalfilesize + }; + + for (const chunkFile of chunkFiles) { try { - await jetpack.removeAsync(chunkedFileDir); + const data = await jetpack.readAsync(chunkFile, 'buffer'); // eslint-disable-line no-await-in-loop + await jetpack.appendAsync(path.join(uploadsDir, tempFile.filename), data); // eslint-disable-line no-await-in-loop } catch (error) { log.error(error); } + } - upload = tempFile; + try { + await jetpack.removeAsync(chunkedFileDir); + } catch (error) { + log.error(error); } + + upload = tempFile; } /* @@ -109,7 +106,7 @@ class uploadPOST extends Route { message: 'Successfully uploaded file BUT IT EXISTED ALREADY', name: exists.name, size: exists.size, - url: `${config.filesServeLocation}/${exists.name}` + url: `${process.env.DOMAIN}/${exists.name}` }); return Util.deleteFile(upload.filename); @@ -147,7 +144,7 @@ class uploadPOST extends Route { message: 'Successfully uploaded file', name: upload.filename, size: upload.size, - url: `${config.filesServeLocation}/${upload.filename}` + url: `${process.env.DOMAIN}/${upload.filename}` }); /* @@ -167,7 +164,7 @@ class uploadPOST extends Route { /* If exif removal has been force service-wide or requested by the user, remove it */ - if (config.uploads.forceStripExif) { // || user.settings.stripExif) { + if (process.env.STRIP_EXIF) { // || user.settings.stripExif) { // Util.removeExif(upload.filename); } @@ -177,11 +174,11 @@ class uploadPOST extends Route { return Util.generateThumbnails(upload.filename); } - uploadFile(req, res, user) { + uploadFile(req, res, db, user) { const busboy = new Busboy({ headers: req.headers, limits: { - fileSize: config.uploads.uploadMaxSize * (1000 * 1000), + fileSize: process.env.MAX_SIZE * (1000 * 1000), files: 1 } }); @@ -209,7 +206,8 @@ class uploadPOST extends Route { Hey ther's a file! Let's upload it. */ busboy.on('file', (fieldname, file, filename, encoding, mimetype) => { - let name, saveTo; + let name; + let saveTo; /* Let check whether the file is part of a chunk upload or if it's a standalone one. @@ -219,15 +217,15 @@ class uploadPOST extends Route { const ext = path.extname(filename).toLowerCase(); if (Util.isExtensionBlocked(ext)) return res.status(400).json({ message: 'This extension is not allowed.' }); - if (!fileToUpload.body.uuid) { - name = Util.getUniqueFilename(filename); - if (!name) return res.status(500).json({ message: 'There was a problem allocating a filename for your upload' }); - saveTo = path.join(__dirname, '..', '..', '..', '..', config.uploads.uploadFolder, name); - } else { + if (fileToUpload.body.uuid) { name = `${filename}.${fileToUpload.body.chunkindex}`; - const chunkDir = path.join(__dirname, '..', '..', '..', '..', config.uploads.uploadFolder, 'chunks', fileToUpload.body.uuid); + const chunkDir = path.join(__dirname, '..', '..', '..', '..', process.env.UPLOAD_FOLDER, 'chunks', fileToUpload.body.uuid); jetpack.dir(chunkDir); - saveTo = path.join(__dirname, '..', '..', '..', '..', config.uploads.uploadFolder, 'chunks', fileToUpload.body.uuid, name); + saveTo = path.join(__dirname, '..', '..', '..', '..', process.env.UPLOAD_FOLDER, 'chunks', fileToUpload.body.uuid, name); + } else { + name = Util.getUniqueFilename(filename); + if (!name) return res.status(500).json({ message: 'There was a problem allocating a filename for your upload' }); + saveTo = path.join(__dirname, '..', '..', '..', '..', process.env.UPLOAD_FOLDER, name); } /* @@ -269,7 +267,7 @@ class uploadPOST extends Route { return res.status(500).json({ message: 'There was an error uploading the file.' }); }); - busboy.on('finish', () => this.processFile(req, res, user, fileToUpload)); + busboy.on('finish', () => this.processFile(req, res, db, user, fileToUpload)); req.pipe(busboy); } } diff --git a/src/api/routes/verifyGET.js b/src/api/routes/verifyGET.js index b6ade59..e588c22 100644 --- a/src/api/routes/verifyGET.js +++ b/src/api/routes/verifyGET.js @@ -5,7 +5,7 @@ class verifyGET extends Route { super('/verify', 'get'); } - run(req, res, user) { + run(req, res, db, user) { const returnUser = { id: user.id, username: user.username, diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index 9ff65f0..32d576f 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -1,6 +1,13 @@ const JWT = require('jsonwebtoken'); -const { server } = require('../../../config'); -const db = require('knex')(server.database); +const db = require('knex')({ + client: process.env.DB_CLIENT, + connection: { + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASS, + database: process.env.DB_DATABASE + } +}); const moment = require('moment'); const log = require('../utils/Log'); @@ -15,12 +22,12 @@ class Route { } authorize(req, res) { - if (this.options.bypassAuth) return this.run(req, res); + if (this.options.bypassAuth) return this.run(req, res, db); if (!req.headers.authorization) return res.status(401).json({ message: 'No authorization header provided' }); const token = req.headers.authorization.split(' ')[1]; if (!token) return res.status(401).json({ message: 'No authorization header provided' }); - return JWT.verify(token, server.secret, async (error, decoded) => { + return JWT.verify(token, process.env.SECRET, async (error, decoded) => { if (error) { log.error(error); return res.status(401).json({ message: 'Your token appears to be invalid' }); @@ -33,13 +40,18 @@ class Route { if (iat && iat < moment(user.passwordEditedAt).format('x')) return res.status(401).json({ message: 'Token expired' }); if (!user.enabled) return res.status(401).json({ message: 'This account has been disabled' }); - return this.run(req, res, user); + return this.run(req, res, db, user); }); } - run(req, res, user) { // eslint-disable-line no-unused-vars + run(req, res, db) { // eslint-disable-line no-unused-vars return; } + + error(res, error) { + log.error(error); + return res.status(500).json({ message: 'There was a problem parsing the request' }); + } } module.exports = Route; diff --git a/src/api/structures/Server.js b/src/api/structures/Server.js index 5ead078..dc72558 100644 --- a/src/api/structures/Server.js +++ b/src/api/structures/Server.js @@ -1,4 +1,5 @@ -const config = require('../../../config'); +require('dotenv').config(); + const log = require('../utils/Log'); const express = require('express'); const helmet = require('helmet'); @@ -8,17 +9,16 @@ const bodyParser = require('body-parser'); const jetpack = require('fs-jetpack'); const path = require('path'); const Database = require('./Database'); -const oneliner = require('one-liner'); const rateLimiter = new RateLimit({ - windowMs: config.server.rateLimits.window, - max: config.server.rateLimits.max, + windowMs: process.env.RATE_LIMIT_WINDOW, + max: process.env.RATE_LIMIT_MAX, delayMs: 0 }); class Server { constructor() { - this.port = config.server.ports.backend; + this.port = process.env.SERVER_PORT; this.server = express(); this.server.set('trust proxy', 1); this.server.use(helmet()); @@ -36,12 +36,6 @@ class Server { // this.server.use(rateLimiter); this.routesFolder = path.join(__dirname, '..', 'routes'); this.database = new Database(); - this.server.get('/config', (req, res) => res.json({ - baseURL: config.backendLocation, - serviceName: config.serviceName, - maxFileSize: config.uploads.uploadMaxSize, - chunkSize: config.uploads.chunkSize - })); } registerAllTheRoutes() { @@ -51,24 +45,12 @@ class Server { if (Array.isArray(RouteClass)) routes = RouteClass; for (const File of routes) { const route = new File(); - this.server[route.method](config.server.routePrefix + route.path, route.authorize.bind(route)); - log.info(`Found route ${route.method.toUpperCase()} ${config.server.routePrefix}${route.path}`); + this.server[route.method](process.env.ROUTE_PREFIX + route.path, route.authorize.bind(route)); + log.info(`Found route ${route.method.toUpperCase()} ${process.env.ROUTE_PREFIX}${route.path}`); } }); } - writeFrontendConfig() { - const template = oneliner` - module.exports = { - baseURL: '${config.backendLocation}', - serviceName: '${config.serviceName}', - maxFileSize: '${config.uploads.uploadMaxSize}', - chunkSize: '${config.uploads.chunkSize}' - }`; - jetpack.write(path.join(__dirname, '..', '..', 'frontend', 'config.js'), template); - log.success('Frontend config file generated successfully'); - } - start() { jetpack.dir('uploads/chunks'); jetpack.dir('uploads/thumbs/square'); diff --git a/src/api/utils/Util.js b/src/api/utils/Util.js index 52cfb03..79e933f 100644 --- a/src/api/utils/Util.js +++ b/src/api/utils/Util.js @@ -1,9 +1,17 @@ -const config = require('../../../config'); +// const config = require('../../../config'); const jetpack = require('fs-jetpack'); const randomstring = require('randomstring'); const path = require('path'); const JWT = require('jsonwebtoken'); -const db = require('knex')(config.server.database); +const db = require('knex')({ + client: process.env.DB_CLIENT, + connection: { + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASS, + database: process.env.DB_DATABASE + } +}); const moment = require('moment'); const log = require('../utils/Log'); const crypto = require('crypto'); @@ -13,10 +21,11 @@ const Zip = require('adm-zip'); const imageExtensions = ['.jpg', '.jpeg', '.bmp', '.gif', '.png', '.webp']; const videoExtensions = ['.webm', '.mp4', '.wmv', '.avi', '.mov']; +const blockedExtensions = process.env.BLOCKED_EXTENSIONS.split(','); class Util { static isExtensionBlocked(extension) { - return config.uploads.blockedExtensions.includes(extension); + return blockedExtensions.includes(extension); } static generateThumbnails(filename) { @@ -36,38 +45,38 @@ class Util { const ExifTransformer = require('exif-be-gone'); const toStream = require('buffer-to-stream'); - const file = await jetpack.readAsync(path.join(__dirname, '..', '..', '..', config.uploads.uploadFolder, filename), 'buffer'); - const writer = jetpack.createWriteStream(path.join(__dirname, '..', '..', '..', config.uploads.uploadFolder, `${filename}.noexif`)); + const file = await jetpack.readAsync(path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, filename), 'buffer'); + const writer = jetpack.createWriteStream(path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, `${filename}.noexif`)); toStream(file).pipe(new ExifTransformer()).pipe(writer); } */ static async generateThumbnailForImage(filename, output) { - const file = await jetpack.readAsync(path.join(__dirname, '..', '..', '..', config.uploads.uploadFolder, filename), 'buffer'); + const file = await jetpack.readAsync(path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, filename), 'buffer'); await sharp(file) .resize(64, 64) .toFormat('png') - .toFile(path.join(__dirname, '..', '..', '..', config.uploads.uploadFolder, 'thumbs', 'square', output)); + .toFile(path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, 'thumbs', 'square', output)); await sharp(file) .resize(225, null) .toFormat('png') - .toFile(path.join(__dirname, '..', '..', '..', config.uploads.uploadFolder, 'thumbs', output)); + .toFile(path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, 'thumbs', output)); } static generateThumbnailForVideo(filename) { - ffmpeg(path.join(__dirname, '..', '..', '..', config.uploads.uploadFolder, filename)) + ffmpeg(path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, filename)) .thumbnail({ timestamps: [0], filename: '%b.png', - folder: path.join(__dirname, '..', '..', '..', config.uploads.uploadFolder, 'thumbs', 'square'), + folder: path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, 'thumbs', 'square'), size: '64x64' }) .on('error', error => log.error(error.message)); - ffmpeg(path.join(__dirname, '..', '..', '..', config.uploads.uploadFolder, filename)) + ffmpeg(path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, filename)) .thumbnail({ timestamps: [0], filename: '%b.png', - folder: path.join(__dirname, '..', '..', '..', config.uploads.uploadFolder, 'thumbs'), + folder: path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, 'thumbs'), size: '150x?' }) .on('error', error => log.error(error.message)); @@ -80,11 +89,11 @@ class Util { } static constructFilePublicLink(file) { - file.url = `${config.filesServeLocation}/${file.name}`; + file.url = `${process.env.DOMAIN}/${file.name}`; const thumb = this.getFileThumbnail(file.name); if (thumb) { - file.thumb = `${config.filesServeLocation}/thumbs/${thumb}`; - file.thumbSquare = `${config.filesServeLocation}/thumbs/square/${thumb}`; + file.thumb = `${process.env.DOMAIN}/thumbs/${thumb}`; + file.thumbSquare = `${process.env.DOMAIN}/thumbs/square/${thumb}`; } return file; } @@ -92,12 +101,13 @@ class Util { static getUniqueFilename(name) { const retry = (i = 0) => { const filename = randomstring.generate({ - length: config.uploads.generatedFilenameLength, + length: process.env.GENERATED_FILENAME_LENGTH, capitalization: 'lowercase' }) + path.extname(name); - const exists = jetpack.exists(path.join(__dirname, '..', '..', '..', config.uploads.uploadFolder, filename)); + const exists = jetpack.exists(path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, filename)); if (!exists) return filename; - if (i < config.uploads.retryFilenameTimes) return retry(i + 1); + if (i < 5) return retry(i + 1); + log.error('Couldnt allocate identifier for file'); return null; }; return retry(); @@ -106,7 +116,7 @@ class Util { static getUniqueAlbumIdentifier() { const retry = async (i = 0) => { const identifier = randomstring.generate({ - length: config.albums.generatedAlbumLinkLength, + length: process.env.GENERATED_ALBUM_LENGTH, capitalization: 'lowercase' }); const exists = await db.table('links').where({ identifier }).first(); @@ -114,7 +124,7 @@ class Util { /* It's funny but if you do i++ the asignment never gets done resulting in an infinite loop */ - if (i < config.albums.retryAlbumLinkTimes) return retry(i + 1); + if (i < 5) return retry(i + 1); log.error('Couldnt allocate identifier for album'); return null; }; @@ -122,7 +132,7 @@ class Util { } static async getFileHash(filename) { - const file = await jetpack.readAsync(path.join(__dirname, '..', '..', '..', config.uploads.uploadFolder, filename), 'buffer'); + const file = await jetpack.readAsync(path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, filename), 'buffer'); if (!file) { log.error(`There was an error reading the file < ${filename} > for hashing`); return null; @@ -140,9 +150,9 @@ class Util { static async deleteFile(filename, deleteFromDB = false) { const thumbName = this.getFileThumbnail(filename); try { - await jetpack.removeAsync(path.join(__dirname, '..', '..', '..', config.uploads.uploadFolder, filename)); - await jetpack.removeAsync(path.join(__dirname, '..', '..', '..', config.uploads.uploadFolder, 'thumbs', thumbName)); - await jetpack.removeAsync(path.join(__dirname, '..', '..', '..', config.uploads.uploadFolder, 'thumbs', 'square', thumbName)); + await jetpack.removeAsync(path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, filename)); + await jetpack.removeAsync(path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, 'thumbs', thumbName)); + await jetpack.removeAsync(path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, 'thumbs', 'square', thumbName)); if (deleteFromDB) { await db.table('files').where('name', filename).delete(); } @@ -156,7 +166,7 @@ class Util { try { const files = await db.table('files').where({ albumId: id }); for (const file of files) { - await jetpack.removeAsync(path.join(__dirname, '..', '..', '..', config.uploads.uploadFolder, file)); + await jetpack.removeAsync(path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, file)); } await db.table('files').where({ albumId: id }).delete(); } catch (error) { @@ -169,7 +179,7 @@ class Util { const token = req.headers.authorization.split(' ')[1]; if (!token) return false; - return JWT.verify(token, config.server.secret, async (error, decoded) => { + return JWT.verify(token, process.env.SECRET, async (error, decoded) => { if (error) { log.error(error); return false; @@ -189,9 +199,9 @@ class Util { try { const zip = new Zip(); for (const file of files) { - zip.addLocalFile(path.join(__dirname, '..', '..', '..', config.uploads.uploadFolder, file)); + zip.addLocalFile(path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, file)); } - zip.writeZip(path.join(__dirname, '..', '..', '..', config.uploads.uploadFolder, 'zips', `${album.userId}-${album.id}.zip`)); + zip.writeZip(path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, 'zips', `${album.userId}-${album.id}.zip`)); } catch (error) { log.error(error); } |