Skip to content

Commit

Permalink
Merge pull request #103 from obsidianforensics/timestamp-sorting-tz-bug
Browse files Browse the repository at this point in the history
Timestamp sorting tz bug
  • Loading branch information
obsidianforensics authored Oct 12, 2021
2 parents 1739b89 + 1d55888 commit 1074cf8
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 6 deletions.
2 changes: 1 addition & 1 deletion hindsight.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ def write_jsonl(analysis_session):
# Hindsight version info
log.info(
'\n' + '#' * 80 +
f'\n### Hindsight v{pyhindsight.__version__} (https://github.com/obsidianforensics/hindsight) ###\n' +
f'\n## Hindsight v{pyhindsight.__version__} (https://github.com/obsidianforensics/hindsight) ##\n' +
'#' * 80)

# Analysis start time
Expand Down
3 changes: 2 additions & 1 deletion pyhindsight/browsers/chrome.py
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,8 @@ def get_cookies(self, path, database, version):

# If the cookie was created and accessed at the same time (only used once), or if the last accessed
# time is 0 (happens on iOS), don't create an accessed row
if new_row.creation_utc != new_row.last_access_utc and accessed_row.last_access_utc != utils.to_datetime(0, self.timezone):
if new_row.creation_utc != new_row.last_access_utc and \
accessed_row.last_access_utc != utils.to_datetime(0, self.timezone):
accessed_row.row_type = 'cookie (accessed)'
accessed_row.timestamp = accessed_row.last_access_utc
results.append(accessed_row)
Expand Down
21 changes: 17 additions & 4 deletions pyhindsight/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,24 @@ def to_datetime(timestamp, timezone=None):
log.warning(f'Exception parsing {timestamp} to datetime: {e}')
return datetime.datetime.fromtimestamp(0)

# Really big Webkit microseconds (17-8 digits), most often cookie expiry dates.
# Really big Webkit microseconds (18 digits), most often cookie expiry dates.
if timestamp >= 253402300800000000:
new_timestamp = datetime.datetime.max
log.warning(f'Timestamp value {timestamp} is too large to convert; replaced with {datetime.datetime.max}')

# Microsecond timestamps past 2038 can be problematic with datetime.utcfromtimestamp(timestamp).
if timestamp > 13700000000000000:
elif timestamp > 13700000000000000:
new_timestamp = datetime.datetime.fromtimestamp(0) \
+ datetime.timedelta(seconds=(timestamp / 1000000) - 11644473600)

# Webkit microseconds (17 digits)
elif timestamp > 12000000000000000: # ts > 1981
new_timestamp = datetime.datetime.utcfromtimestamp((timestamp / 1000000) - 11644473600)

# Epoch microseconds (16 digits)
elif 2500000000000000 > timestamp > 1280000000000000: # 2049 > ts > 2010
new_timestamp = datetime.datetime.utcfromtimestamp(timestamp / 1000000)

# Epoch milliseconds (13 digits)
elif 2500000000000 > timestamp > 1280000000000: # 2049 > ts > 2010
new_timestamp = datetime.datetime.utcfromtimestamp(timestamp / 1000)
Expand All @@ -109,7 +117,12 @@ def to_datetime(timestamp, timezone=None):

# Epoch seconds (10 digits typically, but could be less)
else:
new_timestamp = datetime.datetime.utcfromtimestamp(timestamp)
try:
new_timestamp = datetime.datetime.utcfromtimestamp(timestamp)
except OSError as e:
log.warning(f'Exception parsing {timestamp} to datetime: {e}; '
f'common issue is value is too big for the OS to convert it')
return datetime.datetime.utcfromtimestamp(0)

if timezone is not None:
try:
Expand All @@ -120,7 +133,7 @@ def to_datetime(timestamp, timezone=None):
return new_timestamp
except Exception as e:
log.warning(f'Exception parsing {timestamp} to datetime: {e}')
return datetime.datetime.fromtimestamp(0)
return datetime.datetime.utcfromtimestamp(0)


def friendly_date(timestamp):
Expand Down

0 comments on commit 1074cf8

Please sign in to comment.