def main() -> int: dumpconf = 'dumpconf' initdb = 'initdb' parser = argparse.ArgumentParser() parser.add_argument('action', choices=[dumpconf, initdb, 'refresh'], help='Action to perform') parser.add_argument('-c', '--conf', default=None, help='Configuration file') parser.add_argument('-f', '--force', default=False, action='store_true', help='Force action (default: False)') args = parser.parse_args() if not config.init(args.conf): log.error(f'Cannot parse configuration file: {args.conf}') sys.exit(1) if dumpconf == args.action: config.write(sys.stdout) elif initdb == args.action: RefreshLog.init(create_all=True) else: ClamavRefresh(args).refresh_all() return 0
def setUp(self) -> None: super().setUp() RefreshLog.init(create_all=True) self.s = RefreshLog._session() self.s.query(RefreshLog).delete() self.s.add(RefreshLog(ID1)) self.s.commit()
def setUp(self) -> None: super().setUp() self.ci = _ClamavTestItem(url=URL1, section=self.UNITTEST, option='option', path='path') RefreshLog.init() self.s = RefreshLog._session() self.s.query(RefreshLog).delete() self.s.add(RefreshLog(self.ci, DIGEST_DUMMY)) self.s.commit()
def test_cleanup2(self): file = tempfile.NamedTemporaryFile(mode='w+t', encoding='utf-8', delete=False) file.write(self.UNITTEST) file.close() provider = uuid.uuid4().hex self.ci.section = provider self.ci.path = file.name self.ci.url = URL2 self.s.add(RefreshLog(self.ci, DIGEST_DUMMY)) self.s.commit() self.assertEqual(1, RefreshLog.cleanup_provider(provider))
def setUp(self) -> None: super().setUp() RefreshLog.init() self.s = RefreshLog._session() self.s.query(RefreshLog).delete() cia = _ClamavTestItem('spam', 'option', 'a', path='a') cib = _ClamavTestItem('spamalot', 'option', 'b', path='b') self.s.add(RefreshLog(cia, 'dummy')) self.s.add(RefreshLog(cib, 'dummy')) self.s.commit() self.s.commit()
def test_refresh_age(self): r = RefreshLog(URL_SHA256) r.updated += timedelta(minutes=10) self.s.add(r) self.s.commit() ci = _CI(self.UNITTEST, 'x', URL_SHA256, 'sha256', f'{self.TMPDIR}/x') self.assertFalse(self.ref.refresh(ci))
def test_refresh_digest_match(self): ci = _ClamavTestItem(self.UNITTEST, 'x', URL_MD5, 'md5', f'{self.TMPDIR}/x') r = RefreshLog(ci, DIGEST_MD5) self.s.add(r) self.s.commit() self.assertFalse(self.ref.refresh(ci))
def test_url_blank(self): ci = _ClamavTestItem('unittest4', 'url_blank', '', 'md5', f'{self.TMPDIR}/blank') self.s.add(RefreshLog(ci, DIGEST_DUMMY)) self.s.commit() n = self.ref.refresh_all() self.assertEqual(3, n)
def test_refresh(self): ci = _ClamavTestItem(self.UNITTEST, 'x', URL_MD5, 'md5', f'{self.TMPDIR}/x') self.s.add(RefreshLog(ci, DIGEST_DUMMY)) self.s.commit() n = self.ref.refresh_all() self.assertEqual(3, n)
def test_refresh_age(self): ci = _ClamavTestItem(self.UNITTEST, 'x', URL_SHA256, 'sha256', f'{self.TMPDIR}/x') r = RefreshLog(ci, DIGEST_DUMMY) r.updated += timedelta(minutes=10) self.s.add(r) self.s.commit() self.assertFalse(self.ref.refresh(ci))
def refresh(self, ci: ClamavItem) -> bool: """Refresh a single ClamAV item. :param ci: Item to refresh. :return: True if new payload data was written, False otherwise. """ try: if self.args.force: log.debug(f'{ci.url} refresh forced') elif not RefreshLog.is_outdated(ci.url, ci.interval): log.debug(f'{ci.url} below max age') return False digest = get_digest(ci) if not digest.ok: return False if digest.data and RefreshLog.digest_matches(ci.url, digest.data): log.debug(f'{ci.url} unchanged') RefreshLog.update(ci.url, digest.data) # Update timestamp return False payload = get_payload(ci) if not payload.ok: return False integrity = check_integrity(payload.data, ci.check, digest.data) if not integrity.ok: log.warning(f'{ci.url} {integrity.data}') return False with open(ci.path, 'wb') as f: size = f.write(payload.data) log.info(f'{ci.path} updated ({size} bytes)') RefreshLog.update(ci.url, digest.data) # Update digest and timestamp except OSError as e: # pragma: no cover log.exception(e) return True
def setUp(self) -> None: super().setUp() RefreshLog.init() self.s = RefreshLog._session() self.s.query(RefreshLog).delete() self.s.commit()
def test_match_one(self): x = RefreshLog.url_path_mappings('^spam$') self.assertEqual(1, len(x))
def test_refresh(self): self.s.add(RefreshLog(URL_MD5)) self.s.commit() n = self.ref.refresh_all() self.assertEqual(3, n)
def cleanup_providers() -> int: count = 0 for section in config.sections(): if config.auto_cleanup(section) and not config.is_enabled(section): count += RefreshLog.cleanup_provider(section) return count
def test_duplicate(self): self.s.add(RefreshLog(ID1)) with self.assertRaises(IntegrityError): self.s.commit()
def test_duplicate(self): self.s.add(RefreshLog(self.ci, DIGEST_DUMMY)) with self.assertRaises(IntegrityError): self.s.commit()
def test_insert(self): self.s.add(RefreshLog(ID2)) self.s.commit() self.assertTrue(True) # Must not raise an exception
def test_stamp2(self): RefreshLog.update(ID2, 'XXX') # Must not raise an exception self.assertTrue(True)
def test_cleanup1(self): self.assertEqual(0, RefreshLog.cleanup_provider(self.UNKNOWN))
def test_match_none(self): x = RefreshLog.url_path_mappings('ham') self.assertEqual(0, len(x))
def test_insert(self): self.ci.url = URL2 self.s.add(RefreshLog(self.ci, DIGEST_DUMMY)) self.s.commit() self.assertTrue(True) # Must not raise an exception
def test_refresh_required(self): self.assertTrue(RefreshLog.is_outdated(URL1, 0))
def print_url_path_mappings(self, outfile) -> None: r: RefreshLog for r in RefreshLog.url_path_mappings(self.args.provider): print(f'{r.provider}\t{r.url}\t{r.path}', file=outfile)
def test_stamp1(self): RefreshLog.update(self.ci, DIGEST_DUMMY) # Must not raise an exception self.assertTrue(True)
def test_missing_path(self): self.ci.path = None self.s.add(RefreshLog(self.ci, DIGEST_DUMMY)) with self.assertRaises(IntegrityError): self.s.commit()
def test_match_two(self): x = RefreshLog.url_path_mappings('spam') self.assertEqual(2, len(x))