Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-evtx for openSUSE:Factory checked in at 2021-10-04 18:40:46 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-evtx (Old) and /work/SRC/openSUSE:Factory/.python-evtx.new.2443 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-evtx" Mon Oct 4 18:40:46 2021 rev:10 rq:923006 version:0.7.4 Changes: -------- --- /work/SRC/openSUSE:Factory/python-evtx/python-evtx.changes 2020-05-28 09:16:03.188784467 +0200 +++ /work/SRC/openSUSE:Factory/.python-evtx.new.2443/python-evtx.changes 2021-10-04 18:42:37.414316644 +0200 @@ -1,0 +2,14 @@ +Mon Oct 4 08:29:55 UTC 2021 - Ben Greiner <[email protected]> + +- Update to 0.7.4 + * relax dependencies for most users #72 + * show records by date filter + * handling of invalid dates #43 + * handling of malformed evtx files + * pin dependencies due to py2 deprecation #67 + * testing on pytest 4 +- Drop pytest4.patch merged upstream +- Fix rpmlint alternative link errors +- Fix missing python2-xml requirement + +------------------------------------------------------------------- Old: ---- pytest4.patch python-evtx-0.6.1.tar.gz New: ---- python-evtx-0.7.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-evtx.spec ++++++ --- /var/tmp/diff_new_pack.P93pPB/_old 2021-10-04 18:42:38.062317696 +0200 +++ /var/tmp/diff_new_pack.P93pPB/_new 2021-10-04 18:42:38.066317703 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-evtx # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2021 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,27 +18,31 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define commands dump dump_chunk_slack eid_record_numbers extract_record filter_records info record_structure structure templates +%bcond_without python2 Name: python-evtx -Version: 0.6.1 +Version: 0.7.4 Release: 0 Summary: Windows Event Log files parser License: Apache-2.0 URL: https://github.com/williballenthin/python-evtx Source: https://github.com/williballenthin/python-evtx/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz -# PATCH-FIX-UPSTREAM pytest4.patch gh#williballenthin/python-evtx#66 [email protected] -# make the test suite pass under pytest 4 -Patch0: pytest4.patch BuildRequires: %{python_module hexdump} BuildRequires: %{python_module lxml} BuildRequires: %{python_module pytest} BuildRequires: %{python_module setuptools} +%if %{with python2} +BuildRequires: python2-xml +%endif BuildRequires: dos2unix BuildRequires: fdupes BuildRequires: python-rpm-macros Requires: python-hexdump Requires: python-lxml +%ifpython2 +Requires: python-xml +%endif Requires(post): update-alternatives -Requires(postun): update-alternatives +Requires(postun):update-alternatives BuildArch: noarch %python_subpackages @@ -71,27 +75,22 @@ %pytest %post -for c in %{commands}; do - %python_install_alternative evtx_$c.py -done +%{lua:for c in rpm.expand("%{commands}"):gmatch("%S+") do + print(rpm.expand("%python_install_alternative evtx_" .. c .. ".py")) +end} %postun -for c in %{commands}; do - %python_uninstall_alternative evtx_$c.py -done +%{lua:for c in rpm.expand("%{commands}"):gmatch("%S+") do + print(rpm.expand("%python_uninstall_alternative evtx_" .. c .. ".py")) +end} %files %{python_files} %license LICENSE.TXT %doc README.md -%{python_sitelib}/* -%python_alternative %{_bindir}/evtx_dump.py -%python_alternative %{_bindir}/evtx_dump_chunk_slack.py -%python_alternative %{_bindir}/evtx_eid_record_numbers.py -%python_alternative %{_bindir}/evtx_extract_record.py -%python_alternative %{_bindir}/evtx_filter_records.py -%python_alternative %{_bindir}/evtx_info.py -%python_alternative %{_bindir}/evtx_record_structure.py -%python_alternative %{_bindir}/evtx_structure.py -%python_alternative %{_bindir}/evtx_templates.py +%{python_sitelib}/Evtx +%{python_sitelib}/python_evtx-%{version}*-info +%{lua:for c in rpm.expand("%{commands}"):gmatch("%S+") do + print(rpm.expand("%python_alternative %{_bindir}/evtx_" .. c .. ".py")) +end} %changelog ++++++ python-evtx-0.6.1.tar.gz -> python-evtx-0.7.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-evtx-0.6.1/.github/workflows/publish.yml new/python-evtx-0.7.4/.github/workflows/publish.yml --- old/python-evtx-0.6.1/.github/workflows/publish.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/python-evtx-0.7.4/.github/workflows/publish.yml 2021-03-22 16:59:17.000000000 +0100 @@ -0,0 +1,31 @@ +# This workflows will upload a Python Package using Twine when a release is created +# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries + +name: Upload Python Package + +on: + release: + types: [created] + +jobs: + deploy: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install setuptools wheel twine + - name: Build and publish + env: + TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} + TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + run: | + python setup.py sdist bdist_wheel + twine upload dist/* diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-evtx-0.6.1/.github/workflows/test.yml new/python-evtx-0.7.4/.github/workflows/test.yml --- old/python-evtx-0.6.1/.github/workflows/test.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/python-evtx-0.7.4/.github/workflows/test.yml 2021-03-22 16:59:17.000000000 +0100 @@ -0,0 +1,36 @@ +name: test + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + tests: + name: Tests in ${{ matrix.python }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - python: 2.7 + - python: 3.8 + steps: + - name: Checkout python-evtx with submodules + uses: actions/checkout@v2 + with: + submodules: true + - name: Set up Python ${{ matrix.python }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python }} + - name: Install lxml deps + run: sudo apt-get install -y libxml2-dev libxslt1-dev python-dev zlib1g-dev + - name: Install lxml + run: pip install lxml + - name: Install python-evtx + run: pip install -e .[test] + - name: Run tests + run: pytest tests/ + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-evtx-0.6.1/Evtx/BinaryParser.py new/python-evtx-0.7.4/Evtx/BinaryParser.py --- old/python-evtx-0.6.1/Evtx/BinaryParser.py 2017-07-17 03:15:06.000000000 +0200 +++ new/python-evtx-0.7.4/Evtx/BinaryParser.py 2021-03-22 16:59:17.000000000 +0100 @@ -105,9 +105,12 @@ def parse_filetime(qword): # see http://integriography.wordpress.com/2010/01/16/using-phython-to-parse-and-present-windows-64-bit-timestamps/ + if qword == 0: + return datetime.min + try: return datetime.utcfromtimestamp(float(qword) * 1e-7 - 11644473600) - except ValueError: + except (ValueError, OSError): return datetime.min diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-evtx-0.6.1/Evtx/Evtx.py new/python-evtx-0.7.4/Evtx/Evtx.py --- old/python-evtx-0.6.1/Evtx/Evtx.py 2017-07-17 03:15:06.000000000 +0200 +++ new/python-evtx-0.7.4/Evtx/Evtx.py 2021-03-22 16:59:17.000000000 +0100 @@ -20,10 +20,11 @@ from __future__ import absolute_import import re -import binascii +import sys import mmap -from functools import wraps +import binascii import logging +from functools import wraps import Evtx.Views as e_views from .Nodes import RootNode @@ -157,7 +158,10 @@ @return A boolean that indicates if the first eight bytes of the FileHeader match the expected magic value. """ - return self.magic() == "ElfFile\x00" + try: + return self.magic() == "ElfFile\x00" + except UnicodeDecodeError: + return False def calculate_checksum(self): """ @@ -215,16 +219,26 @@ ofs += (self.current_chunk_number() * 0x10000) return ChunkHeader(self._buf, ofs) - def chunks(self): + def chunks(self, include_inactive=False): """ @return A generator that yields the chunks of the log file starting with the first chunk, which is always found directly - after the FileHeader, and continuing to the end of the file. + after the FileHeader. + + If `include_inactive` is set to true, enumerate chunks beyond those + declared in the file header (and may therefore be corrupt). """ + if include_inactive: + chunk_count = sys.maxsize + else: + chunk_count = self.chunk_count() + + i = 0 ofs = self._offset + self.header_chunk_size() - while ofs + 0x10000 <= len(self._buf): + while ofs + 0x10000 <= len(self._buf) and i < chunk_count: yield ChunkHeader(self._buf, ofs) ofs += 0x10000 + i += 1 def get_record(self, record_num): """ @@ -305,7 +319,10 @@ @return A boolean that indicates if the first eight bytes of the ChunkHeader match the expected magic value. """ - return self.magic() == "ElfChnk\x00" + try: + return self.magic() == "ElfChnk\x00" + except UnicodeDecodeError: + return False def calculate_header_checksum(self): """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-evtx-0.6.1/scripts/evtx_dates.py new/python-evtx-0.7.4/scripts/evtx_dates.py --- old/python-evtx-0.6.1/scripts/evtx_dates.py 1970-01-01 01:00:00.000000000 +0100 +++ new/python-evtx-0.7.4/scripts/evtx_dates.py 2021-03-22 16:59:17.000000000 +0100 @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +from lxml import etree +from datetime import datetime + +from Evtx.Evtx import Evtx +from Evtx.Views import evtx_file_xml_view + +def get_child(node, tag, ns="{http://schemas.microsoft.com/win/2004/08/events/event}"): + return node.find("%s%s" % (ns, tag)) + +def to_lxml(record_xml): + return etree.fromstring("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?>%s" % record_xml.encode('utf-8')) + +def xml_records(filename): + with Evtx(filename) as evtx: + for xml, record in evtx_file_xml_view(evtx.get_file_header()): + try: + yield to_lxml(xml), None + except etree.XMLSyntaxError as e: + yield xml, e + +def parsed_date(dstr): + ts = None + try: + ts = datetime.strptime(dstr, '%Y-%m-%d %H:%M:%S') + except ValueError: + ts = datetime.strptime(dstr, '%Y-%m-%d %H:%M:%S.%f') + return ts + +def event_in_daterange(d, start, end): + is_in_range = True + if d < start: + is_in_range = False + if d > end: + is_in_range = False + return is_in_range + +def matching_records(evtfile, sdatetime, edatetime): + for node, err in xml_records(evtfile): + if err is not None: + continue + else: + sys = get_child(node, "System") + t = parsed_date(get_child(sys, "TimeCreated").get("SystemTime")) + if event_in_daterange(t, sdatetime, edatetime): + yield node + +def main(): + import argparse + parser = argparse.ArgumentParser() + parser.add_argument("evtfile", type=str) + parser.add_argument("start", type=parsed_date, help="Start date/time YYYY-mm-dd HH:MM:SS(.f)") + parser.add_argument("-e", dest="end", type=parsed_date, help="End date/time YYYY-mm-dd HH:MM:SS(.f)", + default=datetime.now()) + args = parser.parse_args() + + for record in matching_records(args.evtfile, args.start, args.end): + print(etree.tostring(record, pretty_print=True)) + + +if __name__ == "__main__": + main() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-evtx-0.6.1/scripts/evtx_eid_record_numbers.py new/python-evtx-0.7.4/scripts/evtx_eid_record_numbers.py --- old/python-evtx-0.6.1/scripts/evtx_eid_record_numbers.py 2017-07-17 03:15:06.000000000 +0200 +++ new/python-evtx-0.7.4/scripts/evtx_eid_record_numbers.py 2021-03-22 16:59:17.000000000 +0100 @@ -20,7 +20,7 @@ args = parser.parse_args() with evtx.Evtx(args.evtx) as log: - for record in log.records: + for record in log.records(): try: node = record.lxml() except lxml.etree.XMLSyntaxError: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-evtx-0.6.1/scripts/evtx_info.py new/python-evtx-0.7.4/scripts/evtx_info.py --- old/python-evtx-0.6.1/scripts/evtx_info.py 2017-07-17 03:15:06.000000000 +0200 +++ new/python-evtx-0.7.4/scripts/evtx_info.py 2021-03-22 16:59:17.000000000 +0100 @@ -72,7 +72,7 @@ print("Information from chunks:") print(" Chunk file (first/last) log (first/last) Header Data") print("- ----- --------------------- --------------------- ------ ------") - for (i, chunk) in enumerate(fh.chunks(), 1): + for (i, chunk) in enumerate(fh.chunks(include_inactive=True), 1): note_string = " " if i == fh.current_chunk_number() + 1: note_string = "*" @@ -80,7 +80,12 @@ note_string = ">" if not chunk.check_magic(): - if chunk.magic() == "\x00\x00\x00\x00\x00\x00\x00\x00": + try: + magic = chunk.magic() + except UnicodeDecodeError: + magic = "" + + if magic == "\x00\x00\x00\x00\x00\x00\x00\x00": print("%s %4d [EMPTY]" % (note_string, i)) else: print("%s %4d [INVALID]" % (note_string, i)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-evtx-0.6.1/scripts/evtx_record_template.py new/python-evtx-0.7.4/scripts/evtx_record_template.py --- old/python-evtx-0.6.1/scripts/evtx_record_template.py 2017-07-17 03:15:06.000000000 +0200 +++ new/python-evtx-0.7.4/scripts/evtx_record_template.py 2021-03-22 16:59:17.000000000 +0100 @@ -18,7 +18,11 @@ with evtx.Evtx(args.evtx) as log: r = log.get_record(args.record) - print(e_views.evtx_template_readable_view(r.root())) + if r is None: + print("error: record not found") + return -1 + else: + print(e_views.evtx_template_readable_view(r.root())) if __name__ == "__main__": diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-evtx-0.6.1/setup.py new/python-evtx-0.7.4/setup.py --- old/python-evtx-0.6.1/setup.py 2017-07-17 03:15:06.000000000 +0200 +++ new/python-evtx-0.7.4/setup.py 2021-03-22 16:59:17.000000000 +0100 @@ -13,7 +13,7 @@ setuptools.setup( name="python-evtx", - version="0.6.1", + version="0.7.4", description="Pure Python parser for recent Windows event log files (.evtx).", long_description=long_description, author="Willi Ballenthin", @@ -23,10 +23,22 @@ packages=setuptools.find_packages(), install_requires=[ 'six', - 'pytest', - 'hexdump', - 'pytest-cov', + 'hexdump==3.3', + + # pin deps for python 2, see #67 + 'more_itertools==5.0.0', + 'zipp==1.0.0', + 'configparser==4.0.2', + 'pyparsing==2.4.7', ], + extras_require={ + # For running unit tests & coverage + "test": [ + 'pytest-cov==2.11.1', + 'pytest==4.6.11', + 'lxml==4.6.3', + ] + }, scripts=['scripts/evtx_dump.py', 'scripts/evtx_dump_chunk_slack.py', 'scripts/evtx_eid_record_numbers.py', Binary files old/python-evtx-0.6.1/tests/data/issue_43.evtx and new/python-evtx-0.7.4/tests/data/issue_43.evtx differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-evtx-0.6.1/tests/fixtures.py new/python-evtx-0.7.4/tests/fixtures.py --- old/python-evtx-0.6.1/tests/fixtures.py 2017-07-17 03:15:06.000000000 +0200 +++ new/python-evtx-0.7.4/tests/fixtures.py 2021-03-22 16:59:17.000000000 +0100 @@ -6,7 +6,6 @@ import pytest [email protected] def system_path(): ''' fetch the file system path of the system.evtx test file. @@ -37,7 +36,6 @@ yield buf [email protected] def security_path(): ''' fetch the file system path of the security.evtx test file. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-evtx-0.6.1/tests/test_issue_43.py new/python-evtx-0.7.4/tests/test_issue_43.py --- old/python-evtx-0.6.1/tests/test_issue_43.py 1970-01-01 01:00:00.000000000 +0100 +++ new/python-evtx-0.7.4/tests/test_issue_43.py 2021-03-22 16:59:17.000000000 +0100 @@ -0,0 +1,27 @@ +import os +import pytest + +import Evtx.Evtx as evtx + +from fixtures import * + + +def get_record_by_num(log, record_num): + for record in log.records(): + if record.record_num() == record_num: + return record + raise KeyError(record_num) + + +def test_issue_43(data_path): + ''' + regression test demonstrating issue 43. + + Args: + data_path (str): the file system path of the test directory. + ''' + with evtx.Evtx(os.path.join(data_path, 'issue_43.evtx')) as log: + bad_rec = get_record_by_num(log, 508) + with pytest.raises(UnicodeDecodeError): + _ = bad_rec.xml() +
