From 541bfedb924ba80f126236656713f769c2194ef2 Mon Sep 17 00:00:00 2001 From: Pitu Date: Tue, 23 Mar 2021 22:35:29 +0900 Subject: wip --- src/api/utils/Util.js | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) (limited to 'src/api/utils') diff --git a/src/api/utils/Util.js b/src/api/utils/Util.js index 6feedd4..b60fca3 100644 --- a/src/api/utils/Util.js +++ b/src/api/utils/Util.js @@ -15,10 +15,30 @@ const StatsGenerator = require('./StatsGenerator'); const blockedExtensions = process.env.BLOCKED_EXTENSIONS.split(','); const preserveExtensions = ['.tar.gz', '.tar.z', '.tar.bz2', '.tar.lzma', '.tar.lzo', '.tar.xz']; -let statsLastSavedTime = null; - class Util { static uploadPath = path.join(__dirname, '../../../', process.env.UPLOAD_FOLDER); + static statsLastSavedTime = null; + static _config = null; + + static get config() { + return (async () => { + if (this._config === null) { + const conf = await db('config').select('key', 'value'); + this._config = conf.reduce((acc, { key, value }) => { + if (typeof value === 'string' || value instanceof String) { + acc[key] = JSON.parse(value); + } else { + acc[key] = value; + } + }, {}); + } + return this._config; + })(); + } + + static invalidateConfigCache() { + this._config = null; + } static uuid() { return uuidv4(); @@ -320,7 +340,7 @@ class Util { // skip generating and saving new stats. if (!force && (!db.userParams.lastMutationTime || - (statsLastSavedTime && statsLastSavedTime > db.userParams.lastMutationTime) + (Util.statsLastSavedTime && Util.statsLastSavedTime > db.userParams.lastMutationTime) ) ) { return; @@ -341,7 +361,7 @@ class Util { await db.table('statistics').insert({ type, data: JSON.stringify(data), createdAt: now, batchId }); } - statsLastSavedTime = now.getTime(); + Util.statsLastSavedTime = now.getTime(); } catch (error) { console.error(error); } -- cgit v1.2.3 From 3f223a9dbfd3f79c1a8f01c6a95d14035cddeefe Mon Sep 17 00:00:00 2001 From: Pitu Date: Thu, 25 Mar 2021 02:03:57 +0900 Subject: feat: implement initial values and saving to db logic --- src/api/utils/Util.js | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'src/api/utils') diff --git a/src/api/utils/Util.js b/src/api/utils/Util.js index b60fca3..e760679 100644 --- a/src/api/utils/Util.js +++ b/src/api/utils/Util.js @@ -40,6 +40,45 @@ class Util { this._config = null; } + static getEnvironmentDefaults() { + return { + routePrefix: process.env.ROUTE_PREFIX || '/api', + rateLimitWindow: process.env.RATE_LIMIT_WINDOW || 2, + rateLimitMax: process.env.RATE_LIMIT_MAX || 5, + secret: process.env.SECRET || randomstring.generate(64), + serviceName: process.env.SERVICE_NAME || 'change-me', + domain: process.env.DOMAIN || `http://localhost:${process.env.SERVER_PORT}`, + chunkSize: process.env.CHUNK_SIZE || 90, + maxSize: process.env.MAX_SIZE || 5000, + generateZips: process.env.GENERATE_ZIPS == undefined ? true : false, + generatedFilenameLength: process.env.GENERATED_FILENAME_LENGTH || 12, + generatedAlbumLength: process.env.GENERATED_ALBUM_LENGTH || 6, + maxLinksPerAlbum: process.env.MAX_LINKS_PER_ALBUM || 5, + uploadFolder: process.env.UPLOAD_FOLDER || 'uploads', + blockedExtensions: process.env.BLOCKED_EXTENSIONS || ['.jar', '.exe', '.msi', '.com', '.bat', '.cmd', '.scr', '.ps1', '.sh'], + publicMode: process.env.PUBLIC_MODE == undefined ? true : false, + userAccounts: process.env.USER_ACCOUNTS == undefined ? true : false, + adminAccount: process.env.ADMIN_ACCOUNT || 'admin', + adminPassword: process.env.ADMIN_PASSWORD || 'admin', + metaThemeColor: process.env.META_THEME_COLOR || '#20222b', + metaDescription: process.env.META_DESCRIPTION || 'Blazing fast file uploader and bunker written in node! 🚀', + metaKeywords: process.env.META_KEYWORDS || 'chibisafe,lolisafe,upload,uploader,file,vue,images,ssr,file uploader,free', + metaTwitterHandle: process.env.META_TWITTER_HANDLE || '@your-handle' + }; + } + + static async writeConfigToDb(config, overwrite = true) { + try { + if (overwrite) { + await db.table('settings').first().update(config); + } else { + await db.table('settings').insert(config); + } + } catch (error) { + console.error(error); + } + } + static uuid() { return uuidv4(); } -- cgit v1.2.3 From 5f5716963dfda3bcae5dab1398d78c933b762c95 Mon Sep 17 00:00:00 2001 From: Pitu Date: Mon, 7 Jun 2021 16:25:02 +0900 Subject: wip --- src/api/utils/Util.js | 1 + 1 file changed, 1 insertion(+) (limited to 'src/api/utils') diff --git a/src/api/utils/Util.js b/src/api/utils/Util.js index e760679..878a542 100644 --- a/src/api/utils/Util.js +++ b/src/api/utils/Util.js @@ -68,6 +68,7 @@ class Util { } static async writeConfigToDb(config, overwrite = true) { + // TODO: Check that the config passes the joi schema validation try { if (overwrite) { await db.table('settings').first().update(config); -- cgit v1.2.3 From 9b28e56e09ef31052935c00c830ceafd481b94f3 Mon Sep 17 00:00:00 2001 From: Pitu Date: Tue, 8 Jun 2021 00:33:01 +0900 Subject: chore: get host from req instead of config --- src/api/utils/Util.js | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'src/api/utils') diff --git a/src/api/utils/Util.js b/src/api/utils/Util.js index 878a542..727851e 100644 --- a/src/api/utils/Util.js +++ b/src/api/utils/Util.js @@ -47,13 +47,11 @@ class Util { rateLimitMax: process.env.RATE_LIMIT_MAX || 5, secret: process.env.SECRET || randomstring.generate(64), serviceName: process.env.SERVICE_NAME || 'change-me', - domain: process.env.DOMAIN || `http://localhost:${process.env.SERVER_PORT}`, chunkSize: process.env.CHUNK_SIZE || 90, maxSize: process.env.MAX_SIZE || 5000, generateZips: process.env.GENERATE_ZIPS == undefined ? true : false, generatedFilenameLength: process.env.GENERATED_FILENAME_LENGTH || 12, generatedAlbumLength: process.env.GENERATED_ALBUM_LENGTH || 6, - maxLinksPerAlbum: process.env.MAX_LINKS_PER_ALBUM || 5, uploadFolder: process.env.UPLOAD_FOLDER || 'uploads', blockedExtensions: process.env.BLOCKED_EXTENSIONS || ['.jar', '.exe', '.msi', '.com', '.bat', '.cmd', '.scr', '.ps1', '.sh'], publicMode: process.env.PUBLIC_MODE == undefined ? true : false, @@ -92,17 +90,18 @@ class Util { return fileTypeMimeObj ? fileTypeMimeObj.mime : undefined; } - static constructFilePublicLink(file) { + static constructFilePublicLink(req, file) { /* TODO: This wont work without a reverse proxy serving both the site and the API under the same domain. Pls fix. */ - file.url = `${process.env.DOMAIN}/${file.name}`; + const host = this.getHost(req); + file.url = `${host}/${file.name}`; const { thumb, preview } = ThumbUtil.getFileThumbnail(file.name) || {}; if (thumb) { - file.thumb = `${process.env.DOMAIN}/thumbs/${thumb}`; - file.thumbSquare = `${process.env.DOMAIN}/thumbs/square/${thumb}`; - file.preview = preview && `${process.env.DOMAIN}/thumbs/preview/${preview}`; + file.thumb = `${host}/thumbs/${thumb}`; + file.thumbSquare = `${host}/thumbs/square/${thumb}`; + file.preview = preview && `${host}/thumbs/preview/${preview}`; } return file; } @@ -265,8 +264,8 @@ class Util { static generateThumbnails = ThumbUtil.generateThumbnails; - static async fileExists(res, exists, filename) { - exists = Util.constructFilePublicLink(exists); + static async fileExists(req, res, exists, filename) { + exists = Util.constructFilePublicLink(req, exists); res.json({ message: 'Successfully uploaded the file.', name: exists.name, @@ -274,7 +273,7 @@ class Util { size: exists.size, url: exists.url, thumb: exists.thumb, - deleteUrl: `${process.env.DOMAIN}/api/file/${exists.id}`, + deleteUrl: `${this.getHost(req)}/api/file/${exists.id}`, repeated: true }); @@ -298,7 +297,7 @@ class Util { .first(); if (dbFile) { - await this.fileExists(res, dbFile, file.data.filename); + await this.fileExists(req, res, dbFile, file.data.filename); return; } @@ -406,6 +405,10 @@ class Util { console.error(error); } } + + static getHost(req) { + return `${req.protocol}://${req.headers.host}`; + } } module.exports = Util; -- cgit v1.2.3 From d3c80127ecdc83cffb9ba9a05f47452fec60287c Mon Sep 17 00:00:00 2001 From: Pitu Date: Tue, 15 Jun 2021 00:12:26 +0900 Subject: chore: update process.env usage --- src/api/utils/ThumbUtil.js | 11 +++++---- src/api/utils/Util.js | 51 +++++++++++++++++------------------------ src/api/utils/generateThumbs.js | 2 +- 3 files changed, 28 insertions(+), 36 deletions(-) (limited to 'src/api/utils') diff --git a/src/api/utils/ThumbUtil.js b/src/api/utils/ThumbUtil.js index d08ecab..fb6e47f 100644 --- a/src/api/utils/ThumbUtil.js +++ b/src/api/utils/ThumbUtil.js @@ -10,11 +10,12 @@ class ThumbUtil { static imageExtensions = ['.jpg', '.jpeg', '.gif', '.png', '.webp']; static videoExtensions = ['.webm', '.mp4', '.wmv', '.avi', '.mov']; - static thumbPath = path.join(__dirname, '../../../', process.env.UPLOAD_FOLDER, 'thumbs'); - static squareThumbPath = path.join(__dirname, '../../../', process.env.UPLOAD_FOLDER, 'thumbs', 'square'); - static videoPreviewPath = path.join(__dirname, '../../../', process.env.UPLOAD_FOLDER, 'thumbs', 'preview'); + static thumbPath = path.join(__dirname, '../../../', 'uploads', 'thumbs'); + static squareThumbPath = path.join(__dirname, '../../../', 'uploads', 'thumbs', 'square'); + static videoPreviewPath = path.join(__dirname, '../../../', 'uploads', 'thumbs', 'preview'); static generateThumbnails(filename) { + if (!filename) return; const ext = path.extname(filename).toLowerCase(); const output = `${filename.slice(0, -ext.length)}.webp`; const previewOutput = `${filename.slice(0, -ext.length)}.webm`; @@ -27,7 +28,7 @@ class ThumbUtil { } static async generateThumbnailForImage(filename, output) { - const filePath = path.join(__dirname, '../../../', process.env.UPLOAD_FOLDER, filename); + const filePath = path.join(__dirname, '../../../', 'uploads', filename); const file = await jetpack.readAsync(filePath, 'buffer'); await sharp(file) @@ -41,7 +42,7 @@ class ThumbUtil { } static async generateThumbnailForVideo(filename, output) { - const filePath = path.join(__dirname, '../../../', process.env.UPLOAD_FOLDER, filename); + const filePath = path.join(__dirname, '../../../', 'uploads', filename); ffmpeg(filePath) .thumbnail({ diff --git a/src/api/utils/Util.js b/src/api/utils/Util.js index 727851e..3780460 100644 --- a/src/api/utils/Util.js +++ b/src/api/utils/Util.js @@ -12,25 +12,22 @@ const log = require('./Log'); const ThumbUtil = require('./ThumbUtil'); const StatsGenerator = require('./StatsGenerator'); -const blockedExtensions = process.env.BLOCKED_EXTENSIONS.split(','); const preserveExtensions = ['.tar.gz', '.tar.z', '.tar.bz2', '.tar.lzma', '.tar.lzo', '.tar.xz']; class Util { - static uploadPath = path.join(__dirname, '../../../', process.env.UPLOAD_FOLDER); + static uploadPath = path.join(__dirname, '../../../', 'uploads'); static statsLastSavedTime = null; static _config = null; static get config() { + if (this._config) return this._config; return (async () => { if (this._config === null) { - const conf = await db('config').select('key', 'value'); - this._config = conf.reduce((acc, { key, value }) => { - if (typeof value === 'string' || value instanceof String) { - acc[key] = JSON.parse(value); - } else { - acc[key] = value; - } - }, {}); + const conf = await db('settings').select('key', 'value'); + this._config = conf.reduce((obj, item) => ( + // eslint-disable-next-line no-sequences + obj[item.key] = typeof item.value === 'string' || item.value instanceof String ? JSON.parse(item.value) : item.value, obj + ), {}); } return this._config; })(); @@ -49,15 +46,15 @@ class Util { serviceName: process.env.SERVICE_NAME || 'change-me', chunkSize: process.env.CHUNK_SIZE || 90, maxSize: process.env.MAX_SIZE || 5000, + // eslint-disable-next-line eqeqeq generateZips: process.env.GENERATE_ZIPS == undefined ? true : false, generatedFilenameLength: process.env.GENERATED_FILENAME_LENGTH || 12, generatedAlbumLength: process.env.GENERATED_ALBUM_LENGTH || 6, - uploadFolder: process.env.UPLOAD_FOLDER || 'uploads', blockedExtensions: process.env.BLOCKED_EXTENSIONS || ['.jar', '.exe', '.msi', '.com', '.bat', '.cmd', '.scr', '.ps1', '.sh'], + // eslint-disable-next-line eqeqeq publicMode: process.env.PUBLIC_MODE == undefined ? true : false, + // eslint-disable-next-line eqeqeq userAccounts: process.env.USER_ACCOUNTS == undefined ? true : false, - adminAccount: process.env.ADMIN_ACCOUNT || 'admin', - adminPassword: process.env.ADMIN_PASSWORD || 'admin', metaThemeColor: process.env.META_THEME_COLOR || '#20222b', metaDescription: process.env.META_DESCRIPTION || 'Blazing fast file uploader and bunker written in node! 🚀', metaKeywords: process.env.META_KEYWORDS || 'chibisafe,lolisafe,upload,uploader,file,vue,images,ssr,file uploader,free', @@ -65,16 +62,16 @@ class Util { }; } - static async writeConfigToDb(config, overwrite = true) { + static async writeConfigToDb(config) { // TODO: Check that the config passes the joi schema validation + if (!config || !config.key || !config.key) return; try { - if (overwrite) { - await db.table('settings').first().update(config); - } else { - await db.table('settings').insert(config); - } + config.value = JSON.stringify(config.value); + await db.table('settings').insert(config); } catch (error) { console.error(error); + } finally { + this.invalidateConfigCache(); } } @@ -83,7 +80,7 @@ class Util { } static isExtensionBlocked(extension) { - return blockedExtensions.includes(extension); + return this.config.blockedExtensions.includes(extension); } static getMimeFromType(fileTypeMimeObj) { @@ -109,7 +106,7 @@ class Util { static getUniqueFilename(extension) { const retry = (i = 0) => { const filename = randomstring.generate({ - length: parseInt(process.env.GENERATED_FILENAME_LENGTH, 10), + length: this.config.generatedFilenameLength, capitalization: 'lowercase' }) + extension; @@ -126,7 +123,7 @@ class Util { static getUniqueAlbumIdentifier() { const retry = async (i = 0) => { const identifier = randomstring.generate({ - length: parseInt(process.env.GENERATED_ALBUM_LENGTH, 10), + length: this.config.generatedAlbumLength, capitalization: 'lowercase' }); const exists = await db @@ -223,7 +220,7 @@ class Util { const token = req.headers.authorization.split(' ')[1]; if (!token) return false; - return JWT.verify(token, process.env.SECRET, async (error, decoded) => { + return JWT.verify(token, this.config.secret, async (error, decoded) => { if (error) { log.error(error); return false; @@ -249,13 +246,7 @@ class Util { zip.addLocalFile(path.join(Util.uploadPath, file)); } zip.writeZip( - path.join( - __dirname, - '../../../', - process.env.UPLOAD_FOLDER, - 'zips', - `${album.userId}-${album.id}.zip` - ) + path.join(__dirname, '../../../', 'uploads', 'zips', `${album.userId}-${album.id}.zip`) ); } catch (error) { log.error(error); diff --git a/src/api/utils/generateThumbs.js b/src/api/utils/generateThumbs.js index d2cd91b..a22fcb6 100644 --- a/src/api/utils/generateThumbs.js +++ b/src/api/utils/generateThumbs.js @@ -6,7 +6,7 @@ const path = require('path'); const ThumbUtil = require('./ThumbUtil'); const start = async () => { - const files = fs.readdirSync(path.join(__dirname, '../../../', process.env.UPLOAD_FOLDER)); + const files = fs.readdirSync(path.join(__dirname, '../../../uploads')); for (const fileName of files) { console.log(`Generating thumb for '${fileName}`); // eslint-disable-next-line no-await-in-loop -- cgit v1.2.3 From 0cae7e9eda3b62c17cfa7ec620913f4a504bc5ee Mon Sep 17 00:00:00 2001 From: Zephyrrus Date: Thu, 17 Jun 2021 16:06:53 +0300 Subject: feat: show validation errors from joi on the frontend --- src/api/utils/Util.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/api/utils') diff --git a/src/api/utils/Util.js b/src/api/utils/Util.js index 3780460..628be82 100644 --- a/src/api/utils/Util.js +++ b/src/api/utils/Util.js @@ -64,7 +64,7 @@ class Util { static async writeConfigToDb(config) { // TODO: Check that the config passes the joi schema validation - if (!config || !config.key || !config.key) return; + if (!config || !config.key) return; try { config.value = JSON.stringify(config.value); await db.table('settings').insert(config); -- cgit v1.2.3 From c131c3a1fc3859908d088dcb04d999d7a3368925 Mon Sep 17 00:00:00 2001 From: Pitu Date: Thu, 17 Jun 2021 23:31:48 +0900 Subject: feat: save correct db info --- src/api/utils/Util.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src/api/utils') diff --git a/src/api/utils/Util.js b/src/api/utils/Util.js index 628be82..bd23fd2 100644 --- a/src/api/utils/Util.js +++ b/src/api/utils/Util.js @@ -62,7 +62,15 @@ class Util { }; } - static async writeConfigToDb(config) { + static async wipeConfigDb() { + try { + await db.table('settings').del(); + } catch (error) { + console.error(error); + } + } + + static async writeConfigToDb(config, wipe = false) { // TODO: Check that the config passes the joi schema validation if (!config || !config.key) return; try { -- cgit v1.2.3 From f42c75c7f4b43161386d40b070e5c7b9b9073213 Mon Sep 17 00:00:00 2001 From: Pitu Date: Fri, 18 Jun 2021 01:45:10 +0900 Subject: feat: add domain to setup process --- src/api/utils/Util.js | 1 + 1 file changed, 1 insertion(+) (limited to 'src/api/utils') diff --git a/src/api/utils/Util.js b/src/api/utils/Util.js index bd23fd2..bea960a 100644 --- a/src/api/utils/Util.js +++ b/src/api/utils/Util.js @@ -39,6 +39,7 @@ class Util { static getEnvironmentDefaults() { return { + domain: process.env.DOMAIN, routePrefix: process.env.ROUTE_PREFIX || '/api', rateLimitWindow: process.env.RATE_LIMIT_WINDOW || 2, rateLimitMax: process.env.RATE_LIMIT_MAX || 5, -- cgit v1.2.3 From 0ec31e23712d5f7672dfafc98af9afcc13703e46 Mon Sep 17 00:00:00 2001 From: Pitu Date: Sat, 19 Jun 2021 02:03:24 +0900 Subject: fix: potentially fix the blocked extensions array splitting --- src/api/utils/Util.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/api/utils') diff --git a/src/api/utils/Util.js b/src/api/utils/Util.js index bea960a..73b2b98 100644 --- a/src/api/utils/Util.js +++ b/src/api/utils/Util.js @@ -51,7 +51,7 @@ class Util { generateZips: process.env.GENERATE_ZIPS == undefined ? true : false, generatedFilenameLength: process.env.GENERATED_FILENAME_LENGTH || 12, generatedAlbumLength: process.env.GENERATED_ALBUM_LENGTH || 6, - blockedExtensions: process.env.BLOCKED_EXTENSIONS || ['.jar', '.exe', '.msi', '.com', '.bat', '.cmd', '.scr', '.ps1', '.sh'], + blockedExtensions: process.env.BLOCKED_EXTENSIONS ? process.env.BLOCKED_EXTENSIONS.split(',') : ['.jar', '.exe', '.msi', '.com', '.bat', '.cmd', '.scr', '.ps1', '.sh'], // eslint-disable-next-line eqeqeq publicMode: process.env.PUBLIC_MODE == undefined ? true : false, // eslint-disable-next-line eqeqeq -- cgit v1.2.3