From 941fa793e0c8361917f701f5c45a3007dc0a97c1 Mon Sep 17 00:00:00 2001 From: faithmry Date: Tue, 9 Dec 2025 05:52:43 +0700 Subject: [PATCH 1/9] fix: fix applePodcastsShows, applePodcastsEpisodes, deviceActivator, health_workouts, wifiIdentifiers, appleMapsSearchHistory and netusage bugs --- scripts/artifacts/appleMapsSearchHistory.py | 106 ++++++++++++-------- scripts/artifacts/applePodcasts.py | 6 +- scripts/artifacts/deviceActivator.py | 1 + scripts/artifacts/health.py | 1 + scripts/artifacts/netusage.py | 23 +++-- scripts/artifacts/wifiIdentifiers.py | 2 + scripts/ilapfuncs.py | 14 ++- 7 files changed, 102 insertions(+), 51 deletions(-) diff --git a/scripts/artifacts/appleMapsSearchHistory.py b/scripts/artifacts/appleMapsSearchHistory.py index e281aa2b8..159ce355b 100644 --- a/scripts/artifacts/appleMapsSearchHistory.py +++ b/scripts/artifacts/appleMapsSearchHistory.py @@ -23,14 +23,28 @@ ) def longbase64proto(longstuff, longtypes): - longstuff = longstuff.split('placeRequest=')[1] - longstuff, _ = blackboxprotobuf.decode_message(base64.b64decode(longstuff), longtypes) - return longstuff + try: + longstuff = longstuff.split('placeRequest=')[1] + # Add padding if needed for base64 decoding + missing_padding = len(longstuff) % 4 + if missing_padding: + longstuff += '=' * (4 - missing_padding) + longstuff, _ = blackboxprotobuf.decode_message(base64.b64decode(longstuff), longtypes) + return longstuff + except (ValueError, IndexError, KeyError, Exception) as e: + return None def shortbase64proto(shortstuff, shorttypes): - shortstuff = shortstuff.split('=')[1] - shortstuff, _ = blackboxprotobuf.decode_message(base64.b64decode(shortstuff), shorttypes) - return shortstuff + try: + shortstuff = shortstuff.split('=')[1] + # Add padding if needed for base64 decoding + missing_padding = len(shortstuff) % 4 + if missing_padding: + shortstuff += '=' * (4 - missing_padding) + shortstuff, _ = blackboxprotobuf.decode_message(base64.b64decode(shortstuff), shorttypes) + return shortstuff + except (ValueError, IndexError, KeyError, Exception) as e: + return None @artifact_processor def get_appleMapsSearchHistory(context): @@ -94,9 +108,10 @@ def get_appleMapsSearchHistory(context): pass try: if protostuff.get('8'): - if (protostuff['8']['2']['1'].get('201')): - usersearchnotinproto = (protostuff['8']['2']['1']['201']['2']['2']['1'].decode()) - except (KeyError, AttributeError, UnicodeDecodeError): + nested = protostuff.get('8', {}).get('2', {}).get('1', {}).get('201', {}).get('2', {}).get('2', {}).get('1') + if nested is not None: + usersearchnotinproto = nested.decode() if isinstance(nested, bytes) else str(nested) + except (KeyError, AttributeError, UnicodeDecodeError, TypeError): #pass try: for mira in (protostuff['8']['2']['1']['4']): @@ -105,25 +120,26 @@ def get_appleMapsSearchHistory(context): if mira['11']['2'].startswith(b'pl'): try: longstuff = longbase64proto(mira['11']['2'].decode(), longtypes) - app = longstuff['1']['1'].decode() - location = longstuff['8']['1']['3'].decode() - geo1 = longstuff['8']['1']['4']['1']['5'] - geo2 = longstuff['8']['1']['4']['1']['6'] - geo3 = longstuff['8']['1']['4']['1']['7'] - geo4 = longstuff['8']['1']['4']['1']['8'] - usersearch1 = longstuff['8']['1']['7']['12']['1'].decode() - usersearch2 = longstuff['8']['1']['7']['10000'].decode() - geo5 = longstuff['8']['1']['7']['5']['1']['1'] - geo6 = longstuff['8']['1']['7']['5']['1']['2'] + if longstuff: + app = longstuff['1']['1'].decode() if isinstance(longstuff['1']['1'], bytes) else str(longstuff['1']['1']) + location = longstuff['8']['1']['3'].decode() if isinstance(longstuff['8']['1']['3'], bytes) else str(longstuff['8']['1']['3']) + geo1 = longstuff['8']['1']['4']['1']['5'] + geo2 = longstuff['8']['1']['4']['1']['6'] + geo3 = longstuff['8']['1']['4']['1']['7'] + geo4 = longstuff['8']['1']['4']['1']['8'] + usersearch1 = longstuff['8']['1']['7']['12']['1'].decode() if isinstance(longstuff['8']['1']['7']['12']['1'], bytes) else str(longstuff['8']['1']['7']['12']['1']) + usersearch2 = longstuff['8']['1']['7']['10000'].decode() if isinstance(longstuff['8']['1']['7']['10000'], bytes) else str(longstuff['8']['1']['7']['10000']) + geo5 = longstuff['8']['1']['7']['5']['1']['1'] + geo6 = longstuff['8']['1']['7']['5']['1']['2'] except (KeyError, AttributeError, UnicodeDecodeError, TypeError): pass try: shortstuff = shortbase64proto(mira['11']['2'].decode(), shorttypes) - - shortlat = (shortstuff['8']['4']['4']['1']['1']) - shortlon = (shortstuff['8']['4']['4']['1']['2']) + if shortstuff: + shortlat = (shortstuff['8']['4']['4']['1']['1']) + shortlon = (shortstuff['8']['4']['4']['1']['2']) except (KeyError, AttributeError, UnicodeDecodeError, TypeError): @@ -137,18 +153,21 @@ def get_appleMapsSearchHistory(context): try: if protostuff.get('7'): shortstuff = shortbase64proto(protostuff.get('7')['1']['1'][0]['2']['1']['4'][8]['11']['2'].decode(), shorttypes) - app = shortstuff['1']['1'].decode() - location = (shortstuff['8']['1']['3'].decode()) - shortlat = (shortstuff['8']['4']['4']['1']['1']) - shortlon = (shortstuff['8']['4']['4']['1']['2']) + if shortstuff: + app = shortstuff['1']['1'].decode() if isinstance(shortstuff['1']['1'], bytes) else str(shortstuff['1']['1']) + location = shortstuff['8']['1']['3'].decode() if isinstance(shortstuff['8']['1']['3'], bytes) else str(shortstuff['8']['1']['3']) + shortlat = (shortstuff['8']['4']['4']['1']['1']) + shortlon = (shortstuff['8']['4']['4']['1']['2']) if (protostuff.get('7')['1']['1'][1]['1'].get('2')): #pp.pprint(protostuff.get('7')['1']['1'][1]['1'].get('2')['4']) #address - pname = (protostuff.get('7')['1']['1'][1]['1'].get('2')['5'].decode()) #place name + pname_val = protostuff.get('7')['1']['1'][1]['1'].get('2')['5'] + pname = pname_val.decode() if isinstance(pname_val, bytes) else str(pname_val) #place name shortadd = '' for parts in (protostuff.get('7')['1']['1'][1]['1'].get('2')['6']): - shortadd = shortadd + parts.decode() + ', ' + part_str = parts.decode() if isinstance(parts, bytes) else str(parts) + shortadd = shortadd + part_str + ', ' shortadd = (shortadd[:-2]) except (KeyError, IndexError, AttributeError, UnicodeDecodeError, TypeError): #pass @@ -167,25 +186,32 @@ def get_appleMapsSearchHistory(context): if mira['11']['2'].startswith(b'pl'): try: longstuff = longbase64proto(mira['11']['2'].decode(), longtypes) - app = longstuff['1']['1'].decode() - location = longstuff['8']['1']['3'].decode() - geo1 = longstuff['8']['1']['4']['1']['5'] - geo2 = longstuff['8']['1']['4']['1']['6'] - geo3 = longstuff['8']['1']['4']['1']['7'] - geo4 = longstuff['8']['1']['4']['1']['8'] - usersearch1 = longstuff['8']['1']['7']['12']['1'].decode() - usersearch2 = longstuff['8']['1']['7']['10000'].decode() - geo5 = longstuff['8']['1']['7']['5']['1']['1'] - geo6 = longstuff['8']['1']['7']['5']['1']['2'] + if longstuff: + app = longstuff['1']['1'].decode() if isinstance(longstuff['1']['1'], bytes) else str(longstuff['1']['1']) + location = longstuff['8']['1']['3'].decode() if isinstance(longstuff['8']['1']['3'], bytes) else str(longstuff['8']['1']['3']) + geo1 = longstuff['8']['1']['4']['1']['5'] + geo2 = longstuff['8']['1']['4']['1']['6'] + geo3 = longstuff['8']['1']['4']['1']['7'] + geo4 = longstuff['8']['1']['4']['1']['8'] + usersearch1 = longstuff['8']['1']['7']['12']['1'].decode() if isinstance(longstuff['8']['1']['7']['12']['1'], bytes) else str(longstuff['8']['1']['7']['12']['1']) + usersearch2 = longstuff['8']['1']['7']['10000'].decode() if isinstance(longstuff['8']['1']['7']['10000'], bytes) else str(longstuff['8']['1']['7']['10000']) + geo5 = longstuff['8']['1']['7']['5']['1']['1'] + geo6 = longstuff['8']['1']['7']['5']['1']['2'] except (KeyError, AttributeError, UnicodeDecodeError, TypeError): pass except (KeyError, IndexError, AttributeError, TypeError): pp = pprint.PrettyPrinter(indent = 0) items = pp.pformat(protostuff['7']['1']['1'][0]['2']['1']['4']) + # Convert items to string if it's bytes or dict to ensure JSON serialization + if isinstance(items, bytes): + items = items.decode('utf-8', errors='replace') + elif isinstance(items, dict): + items = str(items) + data_list.append((modificationdate,app,location,shortadd,pname,shortlat,shortlon,usersearchnotinproto,usersearch1, usersearch2,geo1,geo2,geo3,geo4,geo5,geo6,guid,currentlocation,items, file_found )) modificationdate = app = location = shortadd = pname = shortlat = shortlon = usersearch1 = usersearch2 = geo1 = geo2 = geo3 = geo4 = geo5 = geo6 = guid = items = currentlocation = '' - data_headers = (('Timestamp', 'datetime'),'App','Location','Short Address','Place Name','Latitude','Longitude','Search Not in Protobuf','Search Term','Search Term','Lat1','Lon1','Lat2','Lon2','Lat2','Lon3','Record GUID','Current Location','Items', 'Source File') + data_headers = (('Timestamp', 'datetime'),'App','Location','Short Address','Place Name','Latitude','Longitude','Search Not in Protobuf','Search Term 1','Search Term 2','Lat1','Lon1','Lat2','Lon2','Lat3','Lon3','Record GUID','Current Location','Items', 'Source File') - return data_list, data_headers, 'see Source File for more info' \ No newline at end of file + return data_headers, data_list, 'see Source File for more info' \ No newline at end of file diff --git a/scripts/artifacts/applePodcasts.py b/scripts/artifacts/applePodcasts.py index 5b2723c5a..8c4b93315 100644 --- a/scripts/artifacts/applePodcasts.py +++ b/scripts/artifacts/applePodcasts.py @@ -39,7 +39,7 @@ def get_applePodcastsShows(context): 'Author','Title', 'Feed URL', 'Description', - 'Web Page URL' + 'Web Page URL', 'Source File'] for file_found in context.get_files_found(): @@ -74,7 +74,7 @@ def get_applePodcastsShows(context): data_list.append((timestampadded,timestampdateplayed,timestampdupdate,timestampdowndate,row[4],row[5],row[6],row[7],row[8], file_found)) - return data_list, data_headers, 'see Source File for more info' + return data_headers, data_list, 'see Source File for more info' @artifact_processor def get_applePodcastsEpisodes(context): @@ -139,4 +139,4 @@ def get_applePodcastsEpisodes(context): data_list.append((timestampimport,timestampmeta,timestamplastplay,timestamplastmod,timestampdowndate,row[5],row[6],row[7],row[8],row[9],row[10],row[11],row[12],row[13], file_found)) - return data_list, data_headers, 'see Source File for more info' \ No newline at end of file + return data_headers, data_list, 'see Source File for more info' \ No newline at end of file diff --git a/scripts/artifacts/deviceActivator.py b/scripts/artifacts/deviceActivator.py index 45fb78b10..d2c42462d 100644 --- a/scripts/artifacts/deviceActivator.py +++ b/scripts/artifacts/deviceActivator.py @@ -24,6 +24,7 @@ def deviceActivator(files_found, report_folder, seeker, wrap_text, timezone_offs data_list = [] file_found = str(files_found[0]) + alllines = '' with open(file_found, 'r') as f_in: for line in f_in: line = line.strip() diff --git a/scripts/artifacts/health.py b/scripts/artifacts/health.py index 9a9a149f4..22090e8d9 100644 --- a/scripts/artifacts/health.py +++ b/scripts/artifacts/health.py @@ -499,6 +499,7 @@ def health_workouts(context): CASE workouts.activity_type''' + activity_types + ''' ELSE "Unknown" || "-" || workouts.activity_type END AS 'Type', + NULL AS 'Location Type', strftime('%H:%M:%S', samples.end_date - samples.start_date, 'unixepoch') AS 'Total Time Duration', strftime('%H:%M:%S', workouts.duration, 'unixepoch') AS 'Duration', ''' + distance_and_goals + ''' diff --git a/scripts/artifacts/netusage.py b/scripts/artifacts/netusage.py index d9be1c74a..a7f6fb310 100644 --- a/scripts/artifacts/netusage.py +++ b/scripts/artifacts/netusage.py @@ -48,16 +48,19 @@ def get_netusage(files_found, report_folder, seeker, wrap_text, timezone_offset) for row in all_rows: if row[0] is None: lastconnected = '' - else: - lastconnected = convert_utc_human_to_timezone(convert_ts_human_to_utc(row[0]),timezone_offset) + else: + ts_result = convert_ts_human_to_utc(row[0]) + lastconnected = convert_utc_human_to_timezone(ts_result, timezone_offset) if ts_result else '' if row[1] is None: firstused = '' else: - firstused = convert_utc_human_to_timezone(convert_ts_human_to_utc(row[1]),timezone_offset) + ts_result = convert_ts_human_to_utc(row[1]) + firstused = convert_utc_human_to_timezone(ts_result, timezone_offset) if ts_result else '' if row[2] is None: lastused = '' else: - lastused = convert_utc_human_to_timezone(convert_ts_human_to_utc(row[2]),timezone_offset) + ts_result = convert_ts_human_to_utc(row[2]) + lastused = convert_utc_human_to_timezone(ts_result, timezone_offset) if ts_result else '' data_list.append((lastconnected,firstused,lastused,row[3],row[4],row[5],row[6],row[7],row[8],row[9],row[10],row[11])) @@ -101,8 +104,16 @@ def get_netusage(files_found, report_folder, seeker, wrap_text, timezone_offset) data_headers = ('First Connection Timestamp','Last Connection Timestamp','Network Name','Cell Tower ID/Wifi MAC','Network Type','Bytes In','Bytes Out','Connection Attempts','Connection Successes','Packets In','Packets Out') # Don't remove the comma, that is required to make this a tuple as there is only 1 element data_list = [] for row in all_rows: - firstconncted = convert_utc_human_to_timezone(convert_ts_human_to_utc(row[0]),timezone_offset) - lastconnected = convert_utc_human_to_timezone(convert_ts_human_to_utc(row[1]),timezone_offset) + if row[0] is None: + firstconncted = '' + else: + ts_result = convert_ts_human_to_utc(row[0]) + firstconncted = convert_utc_human_to_timezone(ts_result, timezone_offset) if ts_result else '' + if row[1] is None: + lastconnected = '' + else: + ts_result = convert_ts_human_to_utc(row[1]) + lastconnected = convert_utc_human_to_timezone(ts_result, timezone_offset) if ts_result else '' if row[2] == None: data_list.append((firstconncted,lastconnected,'','',row[3],row[4],row[5],row[6],row[7],row[8],row[9])) diff --git a/scripts/artifacts/wifiIdentifiers.py b/scripts/artifacts/wifiIdentifiers.py index de5016711..059b44b64 100644 --- a/scripts/artifacts/wifiIdentifiers.py +++ b/scripts/artifacts/wifiIdentifiers.py @@ -31,6 +31,8 @@ def wifiIdentifiers(files_found, report_folder, seeker, wrap_text, timezone_offs for key, value in pl.items(): if key == 'Interfaces': for y in value: + if 'IOMACAddress' not in y: + continue hexstring = (y['IOMACAddress']) hexstring = pad_mac_adr("%x:%x:%x:%x:%x:%x" % struct.unpack("BBBBBB",hexstring)) userdefinedname = y['SCNetworkInterfaceInfo']['UserDefinedName'] diff --git a/scripts/ilapfuncs.py b/scripts/ilapfuncs.py index f3033a693..57368a6fa 100644 --- a/scripts/ilapfuncs.py +++ b/scripts/ilapfuncs.py @@ -703,9 +703,11 @@ def timeline(report_folder, tlactivity, data_list, data_headers): db.commit() for entry in data_list: - entry = [str(field) for field in entry] + entry = [str(field) if not isinstance(field, datetime) else field.isoformat() for field in entry] - data_dict = dict(zip(data_headers, entry)) + # Strip tuples from headers for JSON serialization + stripped_headers = strip_tuple_from_headers(data_headers) + data_dict = dict(zip(stripped_headers, entry)) data_str = json.dumps(data_dict) cursor.executemany( @@ -1087,6 +1089,10 @@ def convert_utc_human_to_timezone(utc_time, time_offset): #fetch the timezone information timezone = pytz.timezone(time_offset) + # Handle None value from invalid timestamps + if utc_time is None: + return None + #convert utc to timezone timezone_time = utc_time.astimezone(timezone) @@ -1114,6 +1120,10 @@ def webkit_timestampsconv(webkittime): def convert_ts_human_to_utc(ts): #This is for timestamp in human form if '.' in ts: ts = ts.split('.')[0] + + # Check for invalid year (year 0 or negative) + if ts.startswith('0000-') or ts.startswith('-'): + return None dt = datetime.strptime(ts, '%Y-%m-%d %H:%M:%S') #Make it a datetime object timestamp = dt.replace(tzinfo=timezone.utc) #Make it UTC From b530cab36516a1141695902da1f2d3883f2e3a08 Mon Sep 17 00:00:00 2001 From: faithmry Date: Tue, 9 Dec 2025 07:02:28 +0700 Subject: [PATCH 2/9] fix: fix bluetoothPairedReg bug --- scripts/artifacts/bluetoothPairedReg.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/artifacts/bluetoothPairedReg.py b/scripts/artifacts/bluetoothPairedReg.py index cb1e4ede2..9ef6b3506 100644 --- a/scripts/artifacts/bluetoothPairedReg.py +++ b/scripts/artifacts/bluetoothPairedReg.py @@ -17,7 +17,7 @@ import plistlib import datetime -from scripts.ilapfuncs import artifact_processor, convert_unix_ts_to_str +from scripts.ilapfuncs import artifact_processor, convert_unix_ts_to_utc @artifact_processor @@ -31,7 +31,7 @@ def get_bluetoothPairedReg(files_found, report_folder, seeker, wrap_text, timezo for x in plist.items(): macaddress = x[0] if 'LastSeenTime' in x[1]: - lastseen = convert_unix_ts_to_str(x[1]['LastSeenTime']) + lastseen = convert_unix_ts_to_utc(x[1]['LastSeenTime']) else: lastseen = '' if 'UserNameKey' in x[1]: From ba424af99a6efaf788c50a7456b3d8fd3cc4eedf Mon Sep 17 00:00:00 2001 From: faithmry Date: Tue, 9 Dec 2025 07:11:05 +0700 Subject: [PATCH 3/9] fix: fix alarms, dhcpLeases, keybordAppUsage and appleWifiKnownNetworksTimes bugs --- scripts/ilapfuncs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/ilapfuncs.py b/scripts/ilapfuncs.py index 57368a6fa..9c5ba0e00 100644 --- a/scripts/ilapfuncs.py +++ b/scripts/ilapfuncs.py @@ -1148,7 +1148,7 @@ def convert_ts_human_to_timezone_offset(ts, timezone_offset): def convert_plist_date_to_timezone_offset(plist_date, timezone_offset): if plist_date: - str_date = '%04d-%02d-%02dT%02d:%02d:%02dZ' % ( + str_date = '%04d-%02d-%02dT%02d:%02d:%02d' % ( plist_date.year, plist_date.month, plist_date.day, plist_date.hour, plist_date.minute, plist_date.second ) @@ -1159,7 +1159,7 @@ def convert_plist_date_to_timezone_offset(plist_date, timezone_offset): def convert_plist_date_to_utc(plist_date): if plist_date: - str_date = '%04d-%02d-%02dT%02d:%02d:%02dZ' % ( + str_date = '%04d-%02d-%02dT%02d:%02d:%02d' % ( plist_date.year, plist_date.month, plist_date.day, plist_date.hour, plist_date.minute, plist_date.second ) From 3a9f84999ac03acfb00551bbc67648211f96d2f1 Mon Sep 17 00:00:00 2001 From: faithmry Date: Tue, 9 Dec 2025 07:15:43 +0700 Subject: [PATCH 4/9] fix: fix user_defaults bug --- scripts/artifacts/userDefaults.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/artifacts/userDefaults.py b/scripts/artifacts/userDefaults.py index 626a04d69..728f8c907 100644 --- a/scripts/artifacts/userDefaults.py +++ b/scripts/artifacts/userDefaults.py @@ -56,9 +56,11 @@ def user_defaults(files_found, report_folder, seeker, wrap_text, timezone_offset plist = 'INVALID FILE' else: plist = biplist.readPlist(fp) - for (key,item) in plist.items(): + + if isinstance(plist, dict): + for (key,item) in plist.items(): - data_list.append((bundleid, guid, key, clean_data(item), file_found)) + data_list.append((bundleid, guid, key, clean_data(item), file_found)) if len(data_list) > 0: From 7f46a7acc1f6475b80007741325032a3770633df Mon Sep 17 00:00:00 2001 From: faithmry Date: Tue, 9 Dec 2025 07:16:53 +0700 Subject: [PATCH 5/9] fix: fix system_version_plist bug --- scripts/artifacts/systemVersionPlist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/artifacts/systemVersionPlist.py b/scripts/artifacts/systemVersionPlist.py index ef5999d95..3114a2f63 100644 --- a/scripts/artifacts/systemVersionPlist.py +++ b/scripts/artifacts/systemVersionPlist.py @@ -36,7 +36,7 @@ def system_version_plist(context): sysdiagnose_archive = context.get_source_file_path("sysdiagnose_*.tar.gz") if plist_file: - data_source = system_version_plist + data_source = plist_file pl = get_plist_file_content(data_source) elif 'sysdiagnose_' in sysdiagnose_archive and "IN_PROGRESS_" not in sysdiagnose_archive: tar = tarfile.open(sysdiagnose_archive) From 002ac20f50b3d683731f57b3fea84170d8f11f62 Mon Sep 17 00:00:00 2001 From: faithmry Date: Tue, 9 Dec 2025 07:18:17 +0700 Subject: [PATCH 6/9] fix: fix get_sysdiag_account_devices bug --- scripts/artifacts/sysdiagnose.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/artifacts/sysdiagnose.py b/scripts/artifacts/sysdiagnose.py index dd515fee2..9966c79bc 100644 --- a/scripts/artifacts/sysdiagnose.py +++ b/scripts/artifacts/sysdiagnose.py @@ -57,7 +57,7 @@ def get_sysdiag_account_devices(context): for elem in f["contextDump"]["peers"]: model = elem["permanentInfo"]["model_id"] - m_name = context.get_model_name(model) + m_name = context.get_device_model(model) os_bnum = elem["stableInfo"]["os_version"] os_build = os_bnum.split('(')[1].split(')')[0] os_ver = context.get_os_version(os_build, model) From 5f2bea1adecd10771076cab607b71a8f5ffddf93 Mon Sep 17 00:00:00 2001 From: faithmry Date: Tue, 9 Dec 2025 07:36:26 +0700 Subject: [PATCH 7/9] fix: fix parseCDCache bug --- scripts/artifacts/parsecdCache.py | 39 +++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/scripts/artifacts/parsecdCache.py b/scripts/artifacts/parsecdCache.py index 81f9fcb4c..59f4ef9e3 100644 --- a/scripts/artifacts/parsecdCache.py +++ b/scripts/artifacts/parsecdCache.py @@ -30,15 +30,31 @@ def get_parseCDCache(files_found, report_folder, seeker, wrap_text, timezone_off db = open_sqlite_db_readonly(file_found) cursor = db.cursor() - cursor.execute(''' - select - datetime(engagement_date + 978307200,'unixepoch') as engagement_date, - input, - completion, - transformed, - score - FROM completion_cache_engagement - ''') + + # Check if score column exists + cursor.execute("PRAGMA table_info(completion_cache_engagement)") + columns = [row[1] for row in cursor.fetchall()] + has_score = 'score' in columns + + if has_score: + cursor.execute(''' + select + datetime(engagement_date + 978307200,'unixepoch') as engagement_date, + input, + completion, + transformed, + score + FROM completion_cache_engagement + ''') + else: + cursor.execute(''' + select + datetime(engagement_date + 978307200,'unixepoch') as engagement_date, + input, + completion, + transformed + FROM completion_cache_engagement + ''') all_rows = cursor.fetchall() @@ -47,7 +63,10 @@ def get_parseCDCache(files_found, report_folder, seeker, wrap_text, timezone_off timestamp = convert_ts_human_to_utc(timestamp) timestamp = convert_utc_human_to_timezone(timestamp, timezone_offset) - data_list.append((timestamp, row[1], row[2], row[3], row[4])) + if has_score: + data_list.append((timestamp, row[1], row[2], row[3], row[4])) + else: + data_list.append((timestamp, row[1], row[2], row[3], '')) db.close() From a3317bf2ae23d326153c0dbdffa8a41ad8131d0b Mon Sep 17 00:00:00 2001 From: faithmry Date: Tue, 9 Dec 2025 07:37:26 +0700 Subject: [PATCH 8/9] fix: fix photosDbexif bug --- scripts/artifacts/photosDbexif.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/artifacts/photosDbexif.py b/scripts/artifacts/photosDbexif.py index f857f873c..d29320617 100755 --- a/scripts/artifacts/photosDbexif.py +++ b/scripts/artifacts/photosDbexif.py @@ -66,6 +66,14 @@ def get_photosDbexif(files_found, report_folder, seeker, wrap_text, timezone_off #sqlite portion db = open_sqlite_db_readonly(file_found) cursor = db.cursor() + + # Check if ZASSET table exists + cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='ZASSET'") + if not cursor.fetchone(): + logfunc(f'ZASSET table does not exist in {file_found}') + db.close() + continue + cursor.execute(''' SELECT DATETIME(ZASSET.ZDATECREATED+978307200,'UNIXEPOCH') AS DATECREATED, From 706a7f7b2cfe9e80049fffbff466829722edfed1 Mon Sep 17 00:00:00 2001 From: faithmry Date: Tue, 9 Dec 2025 07:38:02 +0700 Subject: [PATCH 9/9] fix: fix trustedPeers bug --- scripts/artifacts/trustedPeers.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/artifacts/trustedPeers.py b/scripts/artifacts/trustedPeers.py index c8d7221cc..c672879bc 100644 --- a/scripts/artifacts/trustedPeers.py +++ b/scripts/artifacts/trustedPeers.py @@ -33,6 +33,14 @@ def get_trustedPeers(files_found, report_folder, seeker, wrap_text, timezone_off db = open_sqlite_db_readonly(file_found) cursor = db.cursor() + + # Check if table exists + cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='ZESCROWCLIENTMETADATA'") + if not cursor.fetchone(): + logfunc('ZESCROWCLIENTMETADATA table does not exist in database') + db.close() + return + cursor.execute(''' SELECT DISTINCT datetime(client.ZSECUREBACKUPMETADATATIMESTAMP + 978307200, 'unixepoch') AS "Timestamp",