Skip to content

Commit

Permalink
Replaced timelib CopyToIsoFormat with dfDateTime log2timeline#910
Browse files Browse the repository at this point in the history
  • Loading branch information
joachimmetz committed Apr 10, 2021
1 parent e4d6383 commit d254150
Show file tree
Hide file tree
Showing 12 changed files with 205 additions and 149 deletions.
40 changes: 0 additions & 40 deletions plaso/lib/timelib.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
"""

import datetime
import logging

import pytz

Expand Down Expand Up @@ -47,45 +46,6 @@ class Timestamp(object):
# TODO: replace this with a real None implementation.
NONE_TIMESTAMP = 0

@classmethod
def CopyToIsoFormat(cls, timestamp, timezone=pytz.UTC, raise_error=False):
"""Copies the timestamp to an ISO 8601 formatted string.
Args:
timestamp (int): a timestamp containing the number of microseconds since
January 1, 1970, 00:00:00 UTC.
timezone (Optional[pytz.timezone]): time zone.
raise_error (Optional[bool]): True if an OverflowError should be raised
if the timestamp is out of bounds.
Returns:
str: date and time formatted in ISO 8601.
Raises:
OverflowError: if the timestamp value is out of bounds and raise_error
is True.
ValueError: if the timestamp value is missing.
"""
datetime_object = datetime.datetime(1970, 1, 1, 0, 0, 0, 0, tzinfo=pytz.UTC)

if not timestamp:
if raise_error:
raise ValueError('Missing timestamp value')
return datetime_object.isoformat()

try:
datetime_object += datetime.timedelta(microseconds=timestamp)
datetime_object = datetime_object.astimezone(timezone)
except OverflowError as exception:
if raise_error:
raise

logging.error((
'Unable to copy {0:d} to a datetime object with error: '
'{1!s}').format(timestamp, exception))

return datetime_object.isoformat()

@classmethod
def LocaltimeToUTC(cls, timestamp, timezone, is_dst=False):
"""Converts the timestamp in localtime of the timezone to UTC.
Expand Down
58 changes: 25 additions & 33 deletions plaso/output/dynamic.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# -*- coding: utf-8 -*-
"""Dynamic selected delimiter separated values output module."""

from plaso.lib import timelib
import datetime
import pytz

from plaso.output import formatting_helper
from plaso.output import manager
from plaso.output import shared_dsv
Expand Down Expand Up @@ -55,43 +57,33 @@ def _FormatDate(self, event, event_data, event_data_stream):
Returns:
str: date field.
"""
try:
iso_date_time = timelib.Timestamp.CopyToIsoFormat(
event.timestamp, timezone=self._output_mediator.timezone,
raise_error=True)
if event.date_time and self._output_mediator.timezone == pytz.UTC:
year, month, day_of_month = event.date_time.GetDate()
else:
if event.date_time:
timestamp = event.date_time.GetPlasoTimestamp()
else:
timestamp = event.timestamp

return iso_date_time[:10]
try:
datetime_object = datetime.datetime(
1970, 1, 1, 0, 0, 0, 0, tzinfo=pytz.UTC)
datetime_object += datetime.timedelta(microseconds=timestamp)
datetime_object = datetime_object.astimezone(
self._output_mediator.timezone)

except (OverflowError, ValueError):
self._ReportEventError(event, event_data, (
'unable to copy timestamp: {0!s} to a human readable date. '
'Defaulting to: "0000-00-00"').format(event.timestamp))
year = datetime_object.year
month = datetime_object.month
day_of_month = datetime_object.day

return '0000-00-00'
except (OverflowError, TypeError):
year, month, day_of_month = (0, 0, 0)

def _FormatDateTime(self, event, event_data, event_data_stream):
"""Formats a date and time field in ISO 8601 format.
self._ReportEventError(event, event_data, (
'unable to copy timestamp: {0!s} to a human readable date. '
'Defaulting to: "0000-00-00"').format(timestamp))

Args:
event (EventObject): event.
event_data (EventData): event data.
event_data_stream (EventDataStream): event data stream.
Returns:
str: date and time field.
"""
try:
return timelib.Timestamp.CopyToIsoFormat(
event.timestamp, timezone=self._output_mediator.timezone,
raise_error=True)

except (OverflowError, ValueError) as exception:
self._ReportEventError(event, event_data, (
'unable to copy timestamp: {0!s} to a human readable date and time '
'with error: {1!s}. Defaulting to: "0000-00-00T00:00:00"').format(
event.timestamp, exception))

return '0000-00-00T00:00:00'
return '{0:04d}-{1:02d}-{2:02d}'.format(year, month, day_of_month)

def _FormatFilename(self, event, event_data, event_data_stream):
"""Formats the filename.
Expand Down
82 changes: 69 additions & 13 deletions plaso/output/formatting_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
import csv
import datetime
import os
import pytz

from dfvfs.lib import definitions as dfvfs_definitions

from plaso.lib import errors
from plaso.lib import timelib
from plaso.output import logger


Expand Down Expand Up @@ -60,6 +60,43 @@ def __init__(self, output_mediator):
# the check for unused arguments is disabled here.
# pylint: disable=unused-argument

def _FormatDateTime(self, event, event_data, event_data_stream):
"""Formats a date and time field in ISO 8601 format.
Args:
event (EventObject): event.
event_data (EventData): event data.
event_data_stream (EventDataStream): event data stream.
Returns:
str: date and time field with time zone offset.
"""
if event.date_time and self._output_mediator.timezone == pytz.UTC:
iso8601_string = event.date_time.CopyToDateTimeStringISO8601()
return '{0:s}+00:00'.format(iso8601_string[:-1])

if event.date_time:
timestamp = event.date_time.GetPlasoTimestamp()
else:
timestamp = event.timestamp

try:
datetime_object = datetime.datetime(
1970, 1, 1, 0, 0, 0, 0, tzinfo=pytz.UTC)
datetime_object += datetime.timedelta(microseconds=timestamp)
datetime_object = datetime_object.astimezone(
self._output_mediator.timezone)

return datetime_object.isoformat()

except (OverflowError, TypeError) as exception:
self._ReportEventError(event, event_data, (
'unable to copy timestamp: {0!s} to a human readable date and time '
'with error: {1!s}. Defaulting to: "0000-00-00T00:00:00'
'+00:00"').format(timestamp, exception))

return '0000-00-00T00:00:00+00:00'

def _FormatDisplayName(self, event, event_data, event_data_stream):
"""Formats the display name.
Expand Down Expand Up @@ -298,19 +335,33 @@ def _FormatTime(self, event, event_data, event_data_stream):
Returns:
str: time field.
"""
try:
iso_date_time = timelib.Timestamp.CopyToIsoFormat(
event.timestamp, timezone=self._output_mediator.timezone,
raise_error=True)
if event.date_time and self._output_mediator.timezone == pytz.UTC:
hours, minutes, seconds = event.date_time.GetTimeOfDay()
else:
if event.date_time:
timestamp = event.date_time.GetPlasoTimestamp()
else:
timestamp = event.timestamp

return iso_date_time[11:19]
try:
datetime_object = datetime.datetime(
1970, 1, 1, 0, 0, 0, 0, tzinfo=pytz.UTC)
datetime_object += datetime.timedelta(microseconds=timestamp)
datetime_object = datetime_object.astimezone(
self._output_mediator.timezone)

except (OverflowError, ValueError):
self._ReportEventError(event, event_data, (
'unable to copy timestamp: {0!s} to a human readable time. '
'Defaulting to: "--:--:--"').format(event.timestamp))
hours = datetime_object.hour
minutes = datetime_object.minute
seconds = datetime_object.second

except (OverflowError, TypeError):
self._ReportEventError(event, event_data, (
'unable to copy timestamp: {0!s} to a human readable time. '
'Defaulting to: "--:--:--"').format(timestamp))

return '--:--:--'
return '--:--:--'

return '{0:02d}:{1:02d}:{2:02d}'.format(hours, minutes, seconds)

def _FormatTimeZone(self, event, event_data, event_data_stream):
"""Formats a time zone field.
Expand All @@ -323,17 +374,22 @@ def _FormatTimeZone(self, event, event_data, event_data_stream):
Returns:
str: time zone field.
"""
if event.date_time:
timestamp = event.date_time.GetPlasoTimestamp()
else:
timestamp = event.timestamp

# For tzname to work the datetime object must be naive (without a time
# zone).
try:
datetime_object = datetime.datetime(1970, 1, 1, 0, 0, 0, 0)
datetime_object += datetime.timedelta(microseconds=event.timestamp)
datetime_object += datetime.timedelta(microseconds=timestamp)
return self._output_mediator.timezone.tzname(datetime_object)

except OverflowError:
self._ReportEventError(event, event_data, (
'unable to copy timestamp: {0!s} to a human readable time zone. '
'Defaulting to: "00/00/0000"').format(event.timestamp))
'Defaulting to: "00/00/0000"').format(timestamp))

return '-'

Expand Down
39 changes: 27 additions & 12 deletions plaso/output/l2t_csv.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
https://forensicswiki.xyz/wiki/index.php?title=L2T_CSV
"""

import datetime
import pytz

from plaso.lib import definitions
from plaso.lib import errors
from plaso.lib import timelib
from plaso.output import formatting_helper
from plaso.output import interface
from plaso.output import logger
Expand Down Expand Up @@ -92,20 +94,33 @@ def _FormatDate(self, event, event_data, event_data_stream):
Returns:
str: date field.
"""
try:
iso_date_time = timelib.Timestamp.CopyToIsoFormat(
event.timestamp, timezone=self._output_mediator.timezone,
raise_error=True)
if event.date_time and self._output_mediator.timezone == pytz.UTC:
year, month, day_of_month = event.date_time.GetDate()
else:
if event.date_time:
timestamp = event.date_time.GetPlasoTimestamp()
else:
timestamp = event.timestamp

try:
datetime_object = datetime.datetime(
1970, 1, 1, 0, 0, 0, 0, tzinfo=pytz.UTC)
datetime_object += datetime.timedelta(microseconds=timestamp)
datetime_object = datetime_object.astimezone(
self._output_mediator.timezone)

year = datetime_object.year
month = datetime_object.month
day_of_month = datetime_object.day

return '{0:s}/{1:s}/{2:s}'.format(
iso_date_time[5:7], iso_date_time[8:10], iso_date_time[:4])
except (OverflowError, TypeError):
year, month, day_of_month = (0, 0, 0)

except (OverflowError, ValueError):
self._ReportEventError(event, event_data, (
'unable to copy timestamp: {0!s} to a human readable date. '
'Defaulting to: "00/00/0000"').format(event.timestamp))
self._ReportEventError(event, event_data, (
'unable to copy timestamp: {0!s} to a human readable date. '
'Defaulting to: "00/00/0000"').format(timestamp))

return '00/00/0000'
return '{0:02d}/{1:02d}/{2:04d}'.format(month, day_of_month, year)

def _FormatExtraAttributes(self, event, event_data, event_data_stream):
"""Formats an extra attributes field.
Expand Down
21 changes: 8 additions & 13 deletions plaso/output/tln.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
https://forensicswiki.xyz/wiki/index.php?title=TLN
"""

from dfdatetime import posix_time as dfdatetime_posix_time

from plaso.lib import timelib
from plaso.output import formatting_helper
from plaso.output import manager
from plaso.output import shared_dsv
Expand Down Expand Up @@ -48,8 +45,8 @@ def _FormatDescription(self, event, event_data, event_data_stream):
NoFormatterFound: If no event formatter can be found to match the data
type in the event data.
"""
date_time_string = timelib.Timestamp.CopyToIsoFormat(
event.timestamp, timezone=self._output_mediator.timezone)
date_time_string = self._FormatDateTime(
event, event_data, event_data_stream)
timestamp_description = event.timestamp_desc or 'UNKNOWN'

message = self._FormatMessage(event, event_data, event_data_stream)
Expand Down Expand Up @@ -89,14 +86,12 @@ def _FormatTimestamp(self, event, event_data, event_data_stream):
Returns:
str: timestamp.
"""
# TODO: preserve dfdatetime as an object.
date_time = dfdatetime_posix_time.PosixTimeInMicroseconds(
timestamp=event.timestamp)
posix_timestamp = date_time.CopyToPosixTimestamp()
if not posix_timestamp:
posix_timestamp = 0

return '{0:d}'.format(posix_timestamp)
if event.date_time:
posix_timestamp = event.date_time.CopyToPosixTimestamp()
else:
posix_timestamp, _ = divmod(event.timestamp, 1000000)

return '{0:d}'.format(posix_timestamp or 0)


class TLNOutputModule(shared_dsv.DSVOutputModule):
Expand Down
5 changes: 5 additions & 0 deletions tests/containers/test_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# -*- coding: utf-8 -*-
"""Containers related functions and classes for testing."""

from dfdatetime import posix_time as dfdatetime_posix_time

from plaso.containers import events
from plaso.containers import interface

Expand Down Expand Up @@ -29,6 +31,9 @@ def CreateEventFromValues(event_values):
attribute_value)
setattr(event, attribute_name, attribute_value)

event.date_time = dfdatetime_posix_time.PosixTimeInMicroseconds(
timestamp=event.timestamp)

event_data_stream = events.EventDataStream()
for attribute_name in ('path_spec', 'md5_hash', 'sha256_hash'):
attribute_value = copy_of_event_values.pop(attribute_name, None)
Expand Down
10 changes: 0 additions & 10 deletions tests/lib/timelib.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,6 @@
class TimeLibTest(shared_test_lib.BaseTestCase):
"""Tests for timestamp."""

def testCopyToIsoFormat(self):
"""Test the CopyToIsoFormat function."""
timezone = pytz.timezone('CET')

timestamp = shared_test_lib.CopyTimestampFromSring(
'2013-03-14 20:20:08.850041')
date_time_string = timelib.Timestamp.CopyToIsoFormat(
timestamp, timezone=timezone)
self.assertEqual(date_time_string, '2013-03-14T21:20:08.850041+01:00')

def testMonthDict(self):
"""Test the month dict, both inside and outside of scope."""
self.assertEqual(timelib.MONTH_DICT['nov'], 11)
Expand Down
Loading

0 comments on commit d254150

Please sign in to comment.