diff --git a/config.sample.js b/config.sample.js index 4a30a14..059c57d 100644 --- a/config.sample.js +++ b/config.sample.js @@ -173,7 +173,9 @@ module.exports = { scan: { enabled: false, ip: '127.0.0.1', - port: 3310 + port: 3310, + timeout: 180 * 1000, + chunkSize: 64 * 1024 }, /* diff --git a/controllers/uploadController.js b/controllers/uploadController.js index f8beeb6..10fb1d0 100644 --- a/controllers/uploadController.js +++ b/controllers/uploadController.js @@ -567,22 +567,23 @@ uploadsController.formatInfoMap = (req, res, user, infoMap) => { uploadsController.scanFiles = (req, infoMap) => { return new Promise(async (resolve, reject) => { const scanner = req.app.get('clam-scanner') + const timeout = config.uploads.scan.timeout || 5000 + const chunkSize = config.uploads.scan.chunkSize || 64 * 1024 let iteration = 0 for (const info of infoMap) - scanner.scanFile(info.path).then(reply => { + scanner.scanFile(info.path, timeout, chunkSize).then(reply => { + iteration++ + const lastIteration = iteration === infoMap.length if (!reply.includes('OK') || reply.includes('FOUND')) { // eslint-disable-next-line no-control-regex const virus = reply.replace(/^stream: /, '').replace(/ FOUND\u0000$/, '') console.log(`ClamAV: ${info.data.filename}: ${virus} FOUND.`) - return resolve(virus) + return resolve({ virus, lastIteration }) } - - iteration++ - if (iteration === infoMap.length) - resolve(null) + if (lastIteration) resolve(null) }).catch(reject) - }).then(virus => { - if (!virus) return false + }).then(result => { + if (!result) return false // If there is at least one dirty file, then delete all files const set = req.app.get('uploads-set') infoMap.forEach(info => { @@ -595,10 +596,10 @@ uploadsController.scanFiles = (req, infoMap) => { }) // Unfortunately, we will only be returning name of the first virus // even if the current session was made up by multiple virus types - return `Virus detected: ${virus}.` + return `Threat found: ${result.virus}${result.lastIteration ? '' : ', and maybe more'}.` }).catch(error => { console.error(`ClamAV: ${error.toString()}.`) - return `ClamAV: ${error.code}, please contact site owner.` + return `ClamAV: ${error.code !== undefined ? `${error.code} , p` : 'P'}lease contact the site owner.` }) } diff --git a/public/css/home.css b/public/css/home.css index da27c50..ec31346 100644 --- a/public/css/home.css +++ b/public/css/home.css @@ -120,6 +120,14 @@ margin-bottom: 0; } +.uploads .icon:not(.icon-block) { + color: #3794d2; +} + +.uploads .icon.icon-block { + color: #da4453; +} + .uploads progress { margin-top: .5rem; margin-bottom: 1rem; diff --git a/public/js/home.js b/public/js/home.js index 3116412..a03e1f1 100644 --- a/public/js/home.js +++ b/public/js/home.js @@ -272,6 +272,7 @@ page.prepareDropzone = function () { }) page.dropzone.on('error', function (file, error) { + page.updateTemplateIcon(file.previewElement, 'icon-block') file.previewElement.querySelector('.progress').style.display = 'none' file.previewElement.querySelector('.name').innerHTML = file.name file.previewElement.querySelector('.error').innerHTML = error.description || error @@ -312,6 +313,7 @@ page.uploadUrls = function (button) { previewTemplate.innerHTML = page.previewTemplate.trim() const previewElement = previewTemplate.content.firstChild previewElement.querySelector('.name').innerHTML = url + previewElement.querySelector('.progress').removeAttribute('value') previewsContainer.appendChild(previewElement) return { url, @@ -326,11 +328,12 @@ page.uploadUrls = function (button) { function posted (result) { file.previewElement.querySelector('.progress').style.display = 'none' - if (result.success) + if (result.success) { page.updateTemplate(file, result.files[0]) - else + } else { + page.updateTemplateIcon(file.previewElement, 'icon-block') file.previewElement.querySelector('.error').innerHTML = result.description - + } return post(i + 1) } @@ -355,6 +358,13 @@ page.uploadUrls = function (button) { return run() } +page.updateTemplateIcon = function (templateElement, iconClass) { + const iconElement = templateElement.querySelector('.icon') + if (!iconElement) return + iconElement.classList.add(iconClass) + iconElement.style.display = '' +} + page.updateTemplate = function (file, response) { if (!response.url) return @@ -368,12 +378,16 @@ page.updateTemplate = function (file, response) { const img = file.previewElement.querySelector('img') img.setAttribute('alt', response.name || '') img.dataset['src'] = response.url + img.style.display = '' img.onerror = function () { - // Hide images that failed to load - // Consequently also WEBP in browsers that do not have WEBP support (Firefox/IE) + // Hide image elements that fail to load + // Consequently include WEBP in browsers that do not have WEBP support (Firefox/IE) this.style.display = 'none' + file.previewElement.querySelector('.icon').style.display = '' } page.lazyLoad.update(file.previewElement.querySelectorAll('img')) + } else { + page.updateTemplateIcon(file.previewElement, 'icon-doc-inv') } } diff --git a/public/libs/fontello/fontello.css b/public/libs/fontello/fontello.css index 01ac5f7..10c40fc 100644 --- a/public/libs/fontello/fontello.css +++ b/public/libs/fontello/fontello.css @@ -1,11 +1,11 @@ @font-face { font-family: 'fontello'; - src: url('fontello.eot?94642010'); - src: url('fontello.eot?94642010#iefix') format('embedded-opentype'), - url('fontello.woff2?94642010') format('woff2'), - url('fontello.woff?94642010') format('woff'), - url('fontello.ttf?94642010') format('truetype'), - url('fontello.svg?94642010#fontello') format('svg'); + src: url('fontello.eot?13682569'); + src: url('fontello.eot?13682569#iefix') format('embedded-opentype'), + url('fontello.woff2?13682569') format('woff2'), + url('fontello.woff?13682569') format('woff'), + url('fontello.ttf?13682569') format('truetype'), + url('fontello.svg?13682569#fontello') format('svg'); font-weight: normal; font-style: normal; } @@ -15,7 +15,7 @@ @media screen and (-webkit-min-device-pixel-ratio:0) { @font-face { font-family: 'fontello'; - src: url('fontello.svg?94642010#fontello') format('svg'); + src: url('fontello.svg?13682569#fontello') format('svg'); } } */ @@ -77,11 +77,13 @@ .icon-help-circled:before { content: '\e80f'; } /* '' */ .icon-terminal:before { content: '\e810'; } /* '' */ .icon-hammer:before { content: '\e811'; } /* '' */ +.icon-block:before { content: '\e812'; } /* '' */ .icon-privatebin:before { content: '\e817'; } /* '' */ .icon-github-circled:before { content: '\f09b'; } /* '' */ .icon-filter:before { content: '\f0b0'; } /* '' */ .icon-docs:before { content: '\f0c5'; } /* '' */ .icon-gauge:before { content: '\f0e4'; } /* '' */ +.icon-doc-inv:before { content: '\f15b'; } /* '' */ .icon-paper-plane-empty:before { content: '\f1d9'; } /* '' */ .icon-user-plus:before { content: '\f234'; } /* '' */ .icon-chrome:before { content: '\f268'; } /* '' */ diff --git a/public/libs/fontello/fontello.eot b/public/libs/fontello/fontello.eot index a2b664c..f1213e0 100644 Binary files a/public/libs/fontello/fontello.eot and b/public/libs/fontello/fontello.eot differ diff --git a/public/libs/fontello/fontello.svg b/public/libs/fontello/fontello.svg index 7b32da1..dac1bee 100644 --- a/public/libs/fontello/fontello.svg +++ b/public/libs/fontello/fontello.svg @@ -42,6 +42,8 @@ + + @@ -52,6 +54,8 @@ + + diff --git a/public/libs/fontello/fontello.ttf b/public/libs/fontello/fontello.ttf index 85aabee..8427a9e 100644 Binary files a/public/libs/fontello/fontello.ttf and b/public/libs/fontello/fontello.ttf differ diff --git a/public/libs/fontello/fontello.woff b/public/libs/fontello/fontello.woff index 73f965d..dcdf19c 100644 Binary files a/public/libs/fontello/fontello.woff and b/public/libs/fontello/fontello.woff differ diff --git a/public/libs/fontello/fontello.woff2 b/public/libs/fontello/fontello.woff2 index 6af17c1..eb95455 100644 Binary files a/public/libs/fontello/fontello.woff2 and b/public/libs/fontello/fontello.woff2 differ diff --git a/views/_globals.njk b/views/_globals.njk index 2bd81e1..31d64ff 100644 --- a/views/_globals.njk +++ b/views/_globals.njk @@ -16,9 +16,9 @@ v3: CSS and JS files (libs such as bulma, lazyload, etc). v4: Renders in /public/render/* directories (to be used by render.js). #} -{% set v1 = "ix1PYPhEvh" %} +{% set v1 = "DKoamSTKbO" %} {% set v2 = "hiboQUzAzp" %} -{% set v3 = "hiboQUzAzp" %} +{% set v3 = "DKoamSTKbO" %} {% set v4 = "dplQUZqTnf" %} {# diff --git a/views/home.njk b/views/home.njk index 0128a1d..e60e83d 100644 --- a/views/home.njk +++ b/views/home.njk @@ -109,7 +109,8 @@