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 @@