mirror of
https://github.com/BobbyWibowo/lolisafe.git
synced 2025-02-07 13:59:01 +00:00
!! REPLACED ClamAV BACKEND: clamdjs -> clamscan !!
Update your config file!
This commit is contained in:
parent
1902b1c668
commit
88f852584c
@ -112,12 +112,12 @@ You will also need to use this script to overwrite existing thumbnails if you wa
|
|||||||
|
|
||||||
## ClamAV support
|
## ClamAV support
|
||||||
|
|
||||||
This fork has an optional virus scanning support using [ClamAV](https://www.clamav.net/), through [clamdjs](https://github.com/NingLin-P/clamdjs) library.
|
This fork has an optional virus scanning support using [ClamAV](https://www.clamav.net/), utilizing [clamscan](https://github.com/kylefarris/clamscan) library (Linux and OS X only).
|
||||||
|
|
||||||
It will scan new files right after they are uploaded. It will then alert the uploaders of the virus names in ClamAV's database if their files are dirty.
|
It will scan new files right after they are uploaded. It will then alert the uploaders of the virus names in ClamAV's database if their files are dirty.
|
||||||
|
|
||||||
Unfortunately, this will slow down uploads processing as it has to wait for scan results before responding the uploaders, however it's still highly recommended for public usage (or at least if you find Google Safe Search too annoying).
|
Unfortunately, this will slow down uploads processing as it has to wait for the scans before responding the uploaders. However, it's still highly recommended for public usage, or if you're like me who find the constant buzzing from Google Safe Search too annoying.
|
||||||
|
|
||||||
To enable this, make sure you have ClamAV daemon running, then fill in the daemon's IP and port into your config file.
|
To enable this, make sure you have [ClamAV installed](https://github.com/kylefarris/clamscan#to-use-local-binary-method-of-scanning), or additionally have [ClamAV daemon running](https://github.com/kylefarris/clamscan#to-use-clamav-using-tcp-sockets). Afterwards configure `uploads.scan` options, and more importantly its sub-option `clamOptions`. Read more about it in the `config.sample.js` file.
|
||||||
|
|
||||||
From the config file you can also choose to exclude certain extensions from being scanned to lessen the burden on your server.
|
Additionally, you can also configure usergroups bypass, extensions whitelist, and max file size, to lessen the burden on your server.
|
||||||
|
@ -348,13 +348,7 @@ module.exports = {
|
|||||||
Example: 'moderator' = moderators, admins & superadmins.
|
Example: 'moderator' = moderators, admins & superadmins.
|
||||||
*/
|
*/
|
||||||
scan: {
|
scan: {
|
||||||
enabled: false,
|
enabled: true,
|
||||||
|
|
||||||
ip: '127.0.0.1',
|
|
||||||
port: 3310,
|
|
||||||
timeout: 180 * 1000,
|
|
||||||
chunkSize: 64 * 1024,
|
|
||||||
|
|
||||||
groupBypass: 'admin', // Other group names in controllers/permissionController.js
|
groupBypass: 'admin', // Other group names in controllers/permissionController.js
|
||||||
whitelistExtensions: null, /* [
|
whitelistExtensions: null, /* [
|
||||||
'.webp',
|
'.webp',
|
||||||
@ -372,7 +366,27 @@ module.exports = {
|
|||||||
'.mov',
|
'.mov',
|
||||||
'.mkv'
|
'.mkv'
|
||||||
], */
|
], */
|
||||||
maxSize: null // '25MB' // Needs to be in MB
|
// Make sure maxSize is no bigger than the max size you configured for your ClamAV
|
||||||
|
maxSize: null, // Needs to be in MB
|
||||||
|
|
||||||
|
// https://github.com/kylefarris/clamscan/tree/v1.3.3#getting-started
|
||||||
|
// Breaking options (do not use): remove_infected, quarantine_infected
|
||||||
|
// Untested options (may work): scan_log, debug_mode, file_list, scan_recursively
|
||||||
|
// Supported options: clamscan, clamdscan, preference
|
||||||
|
clamOptions: {
|
||||||
|
// clamscan: {},
|
||||||
|
clamdscan: {
|
||||||
|
// When both socket and host+port are specified, it will only use socket
|
||||||
|
socket: '/var/run/clamav/clamd.ctl',
|
||||||
|
host: '127.0.0.1',
|
||||||
|
port: 3310,
|
||||||
|
timeout: 1 * 60 * 1000, // 1 minute
|
||||||
|
multiscan: true,
|
||||||
|
reload_db: false,
|
||||||
|
active: true
|
||||||
|
},
|
||||||
|
preference: 'clamdscan'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -337,7 +337,7 @@ self.actuallyUploadFiles = async (req, res, user, albumid, age) => {
|
|||||||
throw 'Empty files are not allowed.'
|
throw 'Empty files are not allowed.'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utils.clamd.scanner) {
|
if (utils.clamscan.instance) {
|
||||||
const scanResult = await self.scanFiles(req, user, infoMap)
|
const scanResult = await self.scanFiles(req, user, infoMap)
|
||||||
if (scanResult) throw scanResult
|
if (scanResult) throw scanResult
|
||||||
}
|
}
|
||||||
@ -444,7 +444,7 @@ self.actuallyUploadUrls = async (req, res, user, albumid, age) => {
|
|||||||
// If no errors encountered, clear cache of downloaded files
|
// If no errors encountered, clear cache of downloaded files
|
||||||
downloaded.length = 0
|
downloaded.length = 0
|
||||||
|
|
||||||
if (utils.clamd.scanner) {
|
if (utils.clamscan.instance) {
|
||||||
const scanResult = await self.scanFiles(req, user, infoMap)
|
const scanResult = await self.scanFiles(req, user, infoMap)
|
||||||
if (scanResult) throw scanResult
|
if (scanResult) throw scanResult
|
||||||
}
|
}
|
||||||
@ -577,7 +577,7 @@ self.actuallyFinishChunks = async (req, res, user) => {
|
|||||||
infoMap.push({ path: destination, data })
|
infoMap.push({ path: destination, data })
|
||||||
}))
|
}))
|
||||||
|
|
||||||
if (utils.clamd.scanner) {
|
if (utils.clamscan.instance) {
|
||||||
const scanResult = await self.scanFiles(req, user, infoMap)
|
const scanResult = await self.scanFiles(req, user, infoMap)
|
||||||
if (scanResult) throw scanResult
|
if (scanResult) throw scanResult
|
||||||
}
|
}
|
||||||
@ -620,31 +620,30 @@ self.cleanUpChunks = async (uuid, onTimeout) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.scanFiles = async (req, user, infoMap) => {
|
self.scanFiles = async (req, user, infoMap) => {
|
||||||
if (user && utils.clamd.groupBypass && perms.is(user, utils.clamd.groupBypass)) {
|
if (user && utils.clamscan.groupBypass && perms.is(user, utils.clamscan.groupBypass)) {
|
||||||
// logger.log(`[ClamAV]: Skipping ${infoMap.length} file(s), ${utils.clamd.groupBypass} group bypass`)
|
// logger.log(`[ClamAV]: Skipping ${infoMap.length} file(s), ${utils.clamscan.groupBypass} group bypass`)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const foundThreats = []
|
const foundThreats = []
|
||||||
const results = await Promise.all(infoMap.map(async info => {
|
const results = await Promise.all(infoMap.map(async info => {
|
||||||
if (utils.clamd.whitelistExtensions && utils.clamd.whitelistExtensions.includes(info.data.extname)) {
|
if (utils.clamscan.whitelistExtensions && utils.clamscan.whitelistExtensions.includes(info.data.extname)) {
|
||||||
return // logger.log(`[ClamAV]: Skipping ${info.data.filename}, extension whitelisted`)
|
return // logger.log(`[ClamAV]: Skipping ${info.data.filename}, extension whitelisted`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utils.clamd.maxSize && info.data.size > utils.clamd.maxSize) {
|
if (utils.clamscan.maxSize && info.data.size > utils.clamscan.maxSize) {
|
||||||
return // logger.log(`[ClamAV]: Skipping ${info.data.filename}, size ${info.data.size} > ${utils.clamd.maxSize}`)
|
return // logger.log(`[ClamAV]: Skipping ${info.data.filename}, size ${info.data.size} > ${utils.clamscan.maxSize}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const reply = await utils.clamd.scanner.scanFile(info.path, utils.clamd.timeout, utils.clamd.chunkSize)
|
const response = await utils.clamscan.instance.is_infected(info.path)
|
||||||
if (!reply.includes('OK') || reply.includes('FOUND')) {
|
if (response.is_infected) {
|
||||||
// eslint-disable-next-line no-control-regex
|
logger.log(`[ClamAV]: ${info.data.filename}: ${response.viruses.join(', ')}`)
|
||||||
const foundThreat = reply.replace(/^stream: /, '').replace(/ FOUND\u0000$/, '')
|
foundThreats.push(...response.viruses)
|
||||||
logger.log(`[ClamAV]: ${info.data.filename}: ${foundThreat} FOUND.`)
|
|
||||||
foundThreats.push(foundThreat)
|
|
||||||
}
|
}
|
||||||
})).then(() => {
|
})).then(() => {
|
||||||
if (foundThreats.length) {
|
if (foundThreats.length) {
|
||||||
return `Threat found: ${foundThreats[0]}${foundThreats.length > 1 ? ', and more' : ''}.`
|
const more = foundThreats.length > 1
|
||||||
|
return `Threat${more ? 's' : ''} detected: ${foundThreats[0]}${more ? ', and more' : ''}.`
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
logger.error(`[ClamAV]: ${error.toString()}`)
|
logger.error(`[ClamAV]: ${error.toString()}`)
|
||||||
|
@ -12,10 +12,9 @@ const logger = require('./../logger')
|
|||||||
const db = require('knex')(config.database)
|
const db = require('knex')(config.database)
|
||||||
|
|
||||||
const self = {
|
const self = {
|
||||||
clamd: {
|
clamscan: {
|
||||||
scanner: null,
|
instance: null,
|
||||||
timeout: config.uploads.scan.timeout || 5000,
|
version: null,
|
||||||
chunkSize: config.uploads.scan.chunkSize || 64 * 1024,
|
|
||||||
groupBypass: config.uploads.scan.groupBypass || null,
|
groupBypass: config.uploads.scan.groupBypass || null,
|
||||||
whitelistExtensions: (Array.isArray(config.uploads.scan.whitelistExtensions) &&
|
whitelistExtensions: (Array.isArray(config.uploads.scan.whitelistExtensions) &&
|
||||||
config.uploads.scan.whitelistExtensions.length)
|
config.uploads.scan.whitelistExtensions.length)
|
||||||
|
16
lolisafe.js
16
lolisafe.js
@ -1,5 +1,5 @@
|
|||||||
const bodyParser = require('body-parser')
|
const bodyParser = require('body-parser')
|
||||||
const clamd = require('clamdjs')
|
const ClamScan = require('clamscan')
|
||||||
const contentDisposition = require('content-disposition')
|
const contentDisposition = require('content-disposition')
|
||||||
const express = require('express')
|
const express = require('express')
|
||||||
const helmet = require('helmet')
|
const helmet = require('helmet')
|
||||||
@ -245,16 +245,14 @@ safe.use('/api', api)
|
|||||||
logger.log(`Git commit: ${utils.gitHash}`)
|
logger.log(`Git commit: ${utils.gitHash}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clamd scanner
|
// ClamAV scanner
|
||||||
if (config.uploads.scan && config.uploads.scan.enabled) {
|
if (config.uploads.scan && config.uploads.scan.enabled) {
|
||||||
const { ip, port } = config.uploads.scan
|
if (!config.uploads.scan.clamOptions) {
|
||||||
const version = await clamd.version(ip, port)
|
throw 'Missing object config.uploads.scan.clamOptions (check config.sample.js)'
|
||||||
logger.log(`${ip}:${port} ${version}`)
|
|
||||||
|
|
||||||
utils.clamd.scanner = clamd.createScanner(ip, port)
|
|
||||||
if (!utils.clamd.scanner) {
|
|
||||||
throw 'Could not create clamd scanner'
|
|
||||||
}
|
}
|
||||||
|
utils.clamscan.instance = await new ClamScan().init(config.uploads.scan.clamOptions)
|
||||||
|
utils.clamscan.version = await utils.clamscan.instance.get_version().then(s => s.trim())
|
||||||
|
logger.log(`Connection established with ${utils.clamscan.version}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache file identifiers
|
// Cache file identifiers
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
"bcrypt": "~5.0.0",
|
"bcrypt": "~5.0.0",
|
||||||
"blake3": "~2.1.4",
|
"blake3": "~2.1.4",
|
||||||
"body-parser": "~1.19.0",
|
"body-parser": "~1.19.0",
|
||||||
"clamdjs": "~1.0.2",
|
"clamscan": "^1.3.3",
|
||||||
"content-disposition": "~0.5.3",
|
"content-disposition": "~0.5.3",
|
||||||
"express": "~4.17.1",
|
"express": "~4.17.1",
|
||||||
"express-rate-limit": "~5.1.3",
|
"express-rate-limit": "~5.1.3",
|
||||||
|
@ -1183,10 +1183,10 @@ ci-info@^2.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
|
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
|
||||||
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
|
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
|
||||||
|
|
||||||
clamdjs@~1.0.2:
|
clamscan@^1.3.3:
|
||||||
version "1.0.2"
|
version "1.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/clamdjs/-/clamdjs-1.0.2.tgz#42b3c36370979e0c19efd4e3fbc7e0bf0006a8da"
|
resolved "https://registry.yarnpkg.com/clamscan/-/clamscan-1.3.3.tgz#0cf84dc3278cf7a3c81101d3e647842c34c1a825"
|
||||||
integrity sha512-gVnX5ySMULvwYL2ykZQnP4UK4nIK7ftG6z015drJyOFgWpsqXt1Hcq4fMyPwM8LLsxfgfYKLiZi288xuTfmZBQ==
|
integrity sha512-AwaZeyECbqTWwrc5l7lLbA/cbYBTMW+VC77CnIjK3WCwTm1kGL6PHSXgDaEFsVkfrcRvPvSD1oxJpMzET9lqKg==
|
||||||
|
|
||||||
class-utils@^0.3.5:
|
class-utils@^0.3.5:
|
||||||
version "0.3.6"
|
version "0.3.6"
|
||||||
|
Loading…
Reference in New Issue
Block a user