WIP: clamav integration #1223

Closed
pducroquet wants to merge 1 commits from wip/87739-clamav into main
2 changed files with 70 additions and 2 deletions

60
wcs/clamd.py Executable file
View File

@ -0,0 +1,60 @@
#!/usr/bin/env python3
from contextlib import contextmanager
import io
import socket
import struct
import sys
class ClamdClient(object):
def __init__(self, sock_path="/var/run/clamav/clamd.ctl"):
self.sock_path = sock_path
@contextmanager
def _socket(self):
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect(self.sock_path)
sock.settimeout(10)
try:
yield sock
finally:
sock.close()
def _send_command(self, cmd):
with self._socket() as sock:
if type(cmd) is str:
sock.send(b"z%s\x00" % cmd.encode("utf8"))
else:
sock.send(b"z%s\x00" % cmd)
return sock.recv(250).decode("utf8")
def version(self):
return self._send_command("VERSION")
def scan_file(self, filename):
return self._send_command("SCAN %s" % filename)
def scan_stream(self, stream):
with self._socket() as sock:
sock.send(b"zINSTREAM\x00")
chunk_size = 1024
buf = stream.read(chunk_size)
while buf:
sizebuf = struct.pack(b'!L', len(buf)) + buf
sock.send(sizebuf)
buf = stream.read(chunk_size)
sock.send(struct.pack(b'!L', 0))
return sock.recv(250).decode("utf8")
def scan_data(self, data):
return self.scan_stream(io.BytesIO(data))
if __name__ == "__main__":
c = ClamdClient()
print(c.version())
if sys.argv[1] == "-":
print(c.scan_stream(sys.stdin.buffer))
else:
print(c.scan_file(sys.argv[1]))

View File

@ -120,18 +120,26 @@ class FileField(WidgetField):
def convert_value_from_anything(cls, value):
if not value:
return None
from wcs.clamd import ClamdClient
from wcs.variables import LazyFieldVarFile
if isinstance(value, LazyFieldVarFile):
value = value.get_value() # unbox
if hasattr(value, 'base_filename'):
upload = PicklableUpload(value.base_filename, value.content_type or 'application/octet-stream')
# TODO : scan file !
data = None
if hasattr(value, 'get_content'):
upload.receive([value.get_content()])
data = value.get_content()
else:
# native quixote Upload object
upload.receive([value.fp.read()])
data = value.fp.read()
value.fp.seek(0)
clam = ClamdClient()
res = clam.scan_data(data)
if res != b"OK":
raise ValueError("Found a VIRUS, run away, run away !")
upload.receive([data])
return upload
from wcs.workflows import NamedAttachmentsSubstitutionProxy