mirror of
https://github.com/BobbyWibowo/lolisafe.git
synced 2025-01-18 17:21:33 +00:00
Updates
uploadController.js: * Fixed chunk uploads failing when "blockedExtensions" is missing from the config file. config.sample.js: * Renamed "blockedExtensions" to "extensionsFilter", and added a new option named "filterBlacklist". When "filterBlacklist" is set to 'true', all extensions in "extensionsFilter" array will be blacklisted, otherwise it will be a whitelist, so only files with those extensions that can be uploaded. * Renamed "uploads.chunkedUploads.maxSize" to "uploads.chunkedUploads.chunkSize". * Added "uploads.chunkedUploads.noJsMaxSize" which can be used to change the 'displayed' file size on the No-JS uploader page. * Some other phrases updates. _globals.njk: * Updated static files' version string since there is a small update to home.js. other files: * Regular code improvements/tweaks.
This commit is contained in:
parent
6a25eaac05
commit
5bb960756f
@ -40,8 +40,13 @@ module.exports = {
|
||||
// Pages to process for the frontend
|
||||
pages: ['home', 'auth', 'dashboard', 'faq'],
|
||||
|
||||
// Add file extensions here which should be blocked
|
||||
blockedExtensions: [
|
||||
/*
|
||||
If set to true, all extensions in "extensionsFilter" array will be blacklisted,
|
||||
otherwise only files with those extensions that can be uploaded.
|
||||
*/
|
||||
filterBlacklist: true,
|
||||
|
||||
extensionsFilter: [
|
||||
'.jar',
|
||||
'.exe',
|
||||
'.msi',
|
||||
@ -67,15 +72,19 @@ module.exports = {
|
||||
|
||||
/*
|
||||
Chunked uploads.
|
||||
If this is enabled, every files uploaded from the home page will forcibly be chunked
|
||||
by the size specified in uploads.chunkedUploads.maxSize. People will still be able to
|
||||
upload bigger files through the API as long as they don't surpass the limit specified
|
||||
in uploads.maxSize though.
|
||||
Total size of the whole chunks will still be checked against uploads.maxSize too.
|
||||
If this is enabled, every files uploaded from the homepage uploader will forcibly be chunked
|
||||
by the size specified in "chunkSize". People will still be able to upload bigger files with
|
||||
the API as long as they don't surpass the limit specified in the "maxSize" option above.
|
||||
Total size of the whole chunks will also later be checked against the "maxSize" option.
|
||||
No-JS uploader page will not have chunked uploads support, if you want to change the maximum
|
||||
file size 'displayed' on it, you can change the value of "noJsMaxSize".
|
||||
You can also set it to null (or other falsy values) to inherit the value of "maxSize" option.
|
||||
"chunkSize", and "noJsMaxSize" if set, need to be in MB.
|
||||
*/
|
||||
chunkedUploads: {
|
||||
enabled: true,
|
||||
maxSize: '10MB'
|
||||
chunkSize: '10MB',
|
||||
noJsMaxSize: null
|
||||
},
|
||||
|
||||
/*
|
||||
@ -84,8 +93,8 @@ module.exports = {
|
||||
their preferred file name length from the dashboard. The allowed range will
|
||||
be set by "min" and "max". Otherwise it will use "default".
|
||||
Technically it's possible to have "default" outside of the "min" and "max" range,
|
||||
but please not. Once a user has changed to a number within the range, the user will
|
||||
no longer be able to use the default value.
|
||||
but please not. Otherwise, once a user has changed to a value within the range,
|
||||
the user will no longer be able to use the default value.
|
||||
*/
|
||||
fileLength: {
|
||||
min: 4,
|
||||
@ -95,10 +104,10 @@ module.exports = {
|
||||
},
|
||||
|
||||
/*
|
||||
This option will limit how many times it will try to generate random names
|
||||
for uploaded files. If this value is higher than 1, it will help in cases
|
||||
where files with the same name already exists (higher chance with shorter file name length).
|
||||
*/
|
||||
This option will limit how many times it will
|
||||
try to generate a new random name when a collision occurrs.
|
||||
The shorter the file name length is, the higher the chance for a collision to occur.
|
||||
*/
|
||||
maxTries: 1,
|
||||
|
||||
/*
|
||||
|
@ -61,17 +61,15 @@ const upload = multer({
|
||||
fileSize: config.uploads.maxSize
|
||||
},
|
||||
fileFilter (req, file, cb) {
|
||||
// If there are no blocked extensions
|
||||
if (config.blockedExtensions === undefined) {
|
||||
return cb(null, true)
|
||||
}
|
||||
// If there are extensions that have to be filtered
|
||||
if (config.extensionsFilter && config.extensionsFilter.length) {
|
||||
const extname = path.extname(file.originalname).toLowerCase()
|
||||
const match = config.extensionsFilter.some(extension => extname === extension.toLowerCase())
|
||||
|
||||
// If the extension is blocked
|
||||
if (config.blockedExtensions.some(extension => {
|
||||
return path.extname(file.originalname).toLowerCase() === extension.toLowerCase()
|
||||
})) {
|
||||
// eslint-disable-next-line standard/no-callback-literal
|
||||
return cb('This file extension is not allowed.')
|
||||
if ((config.filterBlacklist && match) || (!config.filterBlacklist && !match)) {
|
||||
// eslint-disable-next-line standard/no-callback-literal
|
||||
return cb(`Sorry, ${extname.substr(1).toUpperCase()} files are not permitted for security reasons.`)
|
||||
}
|
||||
}
|
||||
|
||||
if (chunkedUploads) {
|
||||
@ -83,13 +81,12 @@ const upload = multer({
|
||||
}
|
||||
|
||||
const totalFileSize = parseInt(req.body.totalfilesize)
|
||||
if (!isNaN(totalFileSize) && totalFileSize > maxSizeBytes) {
|
||||
if (totalFileSize > maxSizeBytes) {
|
||||
// eslint-disable-next-line standard/no-callback-literal
|
||||
return cb('Chunked upload error. Total file size is larger than maximum file size.')
|
||||
return cb('Chunk error occurred. Total file size is larger than the maximum file size.')
|
||||
}
|
||||
}
|
||||
|
||||
// If the extension is not blocked
|
||||
return cb(null, true)
|
||||
}
|
||||
}).array('files[]')
|
||||
@ -115,7 +112,7 @@ uploadsController.getUniqueRandomName = (length, extension = '', cb) => {
|
||||
// If it still haven't reached allowed maximum tries, then try again
|
||||
if (i < maxTries) { return access(i) }
|
||||
// eslint-disable-next-line standard/no-callback-literal
|
||||
return cb('Could not allocate a unique random name. Try again?')
|
||||
return cb('Sorry, we could not allocate a unique random name. Try again?')
|
||||
})
|
||||
}
|
||||
// Get us a unique random name
|
||||
@ -149,17 +146,18 @@ uploadsController.upload = async (req, res, next) => {
|
||||
|
||||
uploadsController.actuallyUpload = async (req, res, user, albumid) => {
|
||||
const erred = error => {
|
||||
console.log(error)
|
||||
const isError = error instanceof Error
|
||||
if (isError) { console.log(error) }
|
||||
res.json({
|
||||
success: false,
|
||||
description: error.toString()
|
||||
description: isError ? error.toString() : `Error: ${error}`
|
||||
})
|
||||
}
|
||||
|
||||
upload(req, res, async error => {
|
||||
if (error) { return erred(error) }
|
||||
|
||||
if (req.files.length === 0) { return erred(new Error('No files.')) }
|
||||
if (req.files.length === 0) { return erred('No files.') }
|
||||
|
||||
// If chunked uploads is enabled and the uploaded file is a chunk, then just say that it was a success
|
||||
if (chunkedUploads && req.body.uuid) { return res.json({ success: true }) }
|
||||
@ -215,26 +213,28 @@ uploadsController.finishChunks = async (req, res, next) => {
|
||||
|
||||
uploadsController.actuallyFinishChunks = async (req, res, user, albumid) => {
|
||||
const erred = error => {
|
||||
console.log(error)
|
||||
const isError = error instanceof Error
|
||||
if (isError) { console.log(error) }
|
||||
res.json({
|
||||
success: false,
|
||||
description: error.toString()
|
||||
description: isError ? error.toString() : `Error: ${error}`
|
||||
})
|
||||
}
|
||||
|
||||
const files = req.body.files
|
||||
if (!files) { return erred(new Error('Missing files array.')) }
|
||||
if (!files) { return erred('Missing files array.') }
|
||||
|
||||
let iteration = 0
|
||||
const infoMap = []
|
||||
for (const file of files) {
|
||||
const { uuid, original, count } = file
|
||||
if (!uuid || !count) { return erred(new Error('Missing UUID and/or chunks count.')) }
|
||||
if (!uuid) { return erred('Missing UUID.') }
|
||||
if (!count) { return erred('Missing chunks count.') }
|
||||
|
||||
const uuidDir = path.join(chunksDir, uuid)
|
||||
fs.readdir(uuidDir, async (error, chunkNames) => {
|
||||
if (error) { return erred(error) }
|
||||
if (count < chunkNames.length) { return erred(new Error('Chunks count mismatch.')) }
|
||||
if (count < chunkNames.length) { return erred('Chunks count mismatch.') }
|
||||
|
||||
const extension = typeof original === 'string' ? path.extname(original) : ''
|
||||
const length = uploadsController.getFileNameLength(req)
|
||||
|
@ -157,7 +157,7 @@ upload.prepareDropzone = () => {
|
||||
autoProcessQueue: true,
|
||||
headers: { token: upload.token },
|
||||
chunking: upload.chunkedUploads.enabled,
|
||||
chunkSize: parseInt(upload.chunkedUploads.maxSize) * 1000000, // 1000000 B = 1 MB,
|
||||
chunkSize: parseInt(upload.chunkedUploads.chunkSize) * 1000000, // 1000000 B = 1 MB,
|
||||
parallelChunkUploads: false, // when set to true, sometimes it often hangs with hundreds of parallel uploads
|
||||
chunksUploaded: async (file, done) => {
|
||||
file.previewElement.querySelector('.progress').setAttribute('value', 100)
|
||||
|
@ -48,7 +48,6 @@ routes.get('/a/:identifier', async (req, res, next) => {
|
||||
if (config.uploads.generateZips) { enableDownload = true }
|
||||
|
||||
return res.render('album', {
|
||||
layout: false,
|
||||
title: album.name,
|
||||
count: files.length,
|
||||
thumb,
|
||||
|
@ -3,9 +3,8 @@ const routes = require('express').Router()
|
||||
const uploadController = require('./../controllers/uploadController')
|
||||
|
||||
const renderOptions = {
|
||||
layout: false,
|
||||
uploadDisabled: false,
|
||||
maxFileSize: config.uploads.maxSize
|
||||
maxFileSize: config.uploads.chunkedUploads.noJsMaxSize || config.uploads.maxSize
|
||||
}
|
||||
|
||||
if (config.private) {
|
||||
@ -17,7 +16,7 @@ if (config.private) {
|
||||
}
|
||||
|
||||
routes.get('/nojs', async (req, res, next) => {
|
||||
return res.render('nojs', renderOptions)
|
||||
return res.render('nojs', { renderOptions })
|
||||
})
|
||||
|
||||
routes.post('/nojs', (req, res, next) => {
|
||||
@ -25,13 +24,12 @@ routes.post('/nojs', (req, res, next) => {
|
||||
res.json = (...args) => {
|
||||
const result = args[0]
|
||||
|
||||
const _renderOptions = {}
|
||||
Object.assign(_renderOptions, renderOptions)
|
||||
const options = { renderOptions }
|
||||
|
||||
_renderOptions.errorMessage = result.success ? '' : (result.description || 'An unexpected error occurred.')
|
||||
_renderOptions.files = result.files || [{}]
|
||||
options.errorMessage = result.success ? '' : (result.description || 'An unexpected error occurred.')
|
||||
options.files = result.files || [{}]
|
||||
|
||||
return res.render('nojs', _renderOptions)
|
||||
return res.render('nojs', options)
|
||||
}
|
||||
|
||||
return uploadController.upload(req, res, next)
|
||||
|
@ -10,7 +10,7 @@
|
||||
This will be appended to all CSS and JS files,
|
||||
and should be changed on every updates to make sure clients load the very latest version of them.
|
||||
#}
|
||||
{% set v = "8HSPG0eoRX" %}
|
||||
{% set v = "aSRDjST7cs" %}
|
||||
|
||||
{#
|
||||
These will be the links in the homepage and the No-JS uploader.
|
||||
|
@ -24,8 +24,7 @@
|
||||
<h2 class='subtitle'>What is safe.fiery.me?</h2>
|
||||
<article class="message">
|
||||
<div class="message-body">
|
||||
safe.fiery.me is merely another clone of lolisafe. We accept your files, photos, documents, anything, and give you back a shareable link for you to send to others.<br> lolisafe itself is an easy to use, open source and completely free file
|
||||
upload service.
|
||||
safe.fiery.me is merely another clone of <a href="https://github.com/WeebDev/lolisafe" target="_blank">lolisafe</a>. We accept your files, photos, documents, anything, and give you back a shareable link for you to send to others.
|
||||
</div>
|
||||
</article>
|
||||
|
||||
@ -39,7 +38,8 @@
|
||||
<h2 class='subtitle'>How can I keep track of my uploads?</h2>
|
||||
<article class="message">
|
||||
<div class="message-body">
|
||||
Simply create a user on the site and every upload will be associated with your account, granting you access to your uploaded files through our dashboard.<br> By having an account, you will also be able to set file name length for your new
|
||||
Simply create a user on the site and every upload will be associated with your account, granting you access to your uploaded files through our dashboard.<br>
|
||||
By having an account, you will also be able to set file name length for your new
|
||||
uploads!
|
||||
</div>
|
||||
</article>
|
||||
@ -47,16 +47,16 @@
|
||||
<h2 class='subtitle'>Do you have any No-JS uploader?</h2>
|
||||
<article class="message">
|
||||
<div class="message-body">
|
||||
Yes, check out <a href="../nojs" target="_blank">this page</a>.<br> Unfortunately you will not be able to associate your uploads to your account, if you have any.<br> Then again, if you want to use the No-JS uploader, then it's very likely
|
||||
that you will not use the Dashboard anyways.
|
||||
Yes, check out <a href="nojs" target="_blank">this page</a>.<br>
|
||||
Unfortunately you will not be able to associate your uploads to your account, if you have any.<br>
|
||||
Then again, if you want to use the No-JS uploader, then it's very likely that you will not use the Dashboard anyways.
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<h2 class='subtitle'>What are albums?</h2>
|
||||
<article class="message">
|
||||
<div class="message-body">
|
||||
Albums are a simple way of sorting uploads together. Right now you can create albums through the dashboard, then afterwards you can use them through the homepage uploader or with <a href="https://chrome.google.com/webstore/detail/loli-safe-uploader/enkkmplljfjppcdaancckgilmgoiofnj"
|
||||
target="_blank">our chrome extension</a>, which will enable you to <strong>right click -> send to lolisafe</strong> or to a desired album if you have any. You will probably have to change some things involving <b>https://safe.fiery.me/api/upload</b> if you want to use the extension though.
|
||||
Albums are a simple way of sorting uploads together. Right now you can create albums through the dashboard, then afterwards you can use them through the homepage uploader or with <a href="https://chrome.google.com/webstore/detail/loli-safe-uploader/enkkmplljfjppcdaancckgilmgoiofnj" target="_blank">our chrome extension</a>, which will enable you to <strong>right click -> send to lolisafe</strong> or to a desired album if you have any. You will probably have to change some things involving <b>https://safe.fiery.me/api/upload</b> if you want to use the extension though.
|
||||
</div>
|
||||
</article>
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
<h2 class="subtitle">{{ globals.home_subtitle | safe }}</h2>
|
||||
|
||||
<h3 class="subtitle" id="maxFileSize">
|
||||
Maximum upload size per file is {{ maxFileSize }}
|
||||
Maximum upload size per file is {{ renderOptions.maxFileSize }}
|
||||
</h3>
|
||||
|
||||
<div class="columns is-gapless">
|
||||
@ -29,8 +29,8 @@
|
||||
</p>
|
||||
</div>
|
||||
<div class="content">
|
||||
{% if uploadDisabled -%}
|
||||
<a class="button is-danger" style="display: flex" href="auth">{{ uploadDisabled }}</a>
|
||||
{% if renderOptions.uploadDisabled -%}
|
||||
<a class="button is-danger" style="display: flex" href="auth">{{ renderOptions.uploadDisabled }}</a>
|
||||
{%- else -%}
|
||||
<form id="form" action="" method="post" enctype="multipart/form-data">
|
||||
<div class="field">
|
||||
|
Loading…
Reference in New Issue
Block a user