Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ACKNOWLEDGEMENTS
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,11 @@ Copied with permission from [Digital Corpora](https://digitalcorpora.org/):
* ios/com.apple.commcenter.data.plist
* ios/com.apple.MobileBackup.plist
* ios/healthdb_secure_iOS_13_4_1.sqlite
* ios/healthdb_secure_iOS_13_3_1.sqlite
* ios/healthdb_secure_iOS_13_4_1.sqlite
* ios/healthdb_secure_iOS_15.sqlite
* ios/healthdb_secure_iOS_16.sqlite
* ios/healthdb_secure_iOS_17.sqlite
* ios/IMODb2.sqlite
* ios/NoteStore.sqlite
* viber_data
195 changes: 192 additions & 3 deletions plaso/data/formatters/ios.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ message:
- 'Earned Date: {earned_date}'
- 'Value: {value_in_canonical_unit} {value_canonical_unit}'
- 'Creator Device ID: {creator_device}'
- 'Sync Provenance: {sync_provenance}'
- 'Synchronization Provenance: {synchronization_provenance}'
short_message:
- 'Achievement: {template_unique_name}'
- 'Value: {value_in_canonical_unit}'
Expand All @@ -107,6 +107,26 @@ short_source: 'SQLITE'
source: 'iOS Health database'
---
type: 'conditional'
data_type: 'ios:health:all_watch_sleep_ios17'
enumeration_helpers:
- input_attribute: 'sleep_state_code'
output_attribute: 'sleep_state_label'
default_value: 'UNKNOWN'
values:
1: 'In Bed'
2: 'Awake'
3: 'REM'
4: 'Core'
5: 'Deep'
message:
- 'Sleep State: {sleep_state_label}'
- 'Duration: {sleep_state_hms}'
short_message:
- '{sleep_state_label} for {sleep_state_hms}'
short_source: 'SQLITE'
source: 'iOS Health database'
---
type: 'conditional'
data_type: 'ios:health:headphone_audio_levels'
message:
- 'Sound Level: {decibels} dB'
Expand Down Expand Up @@ -167,6 +187,22 @@ short_source: 'SQLITE'
source: 'iOS Health database'
---
type: 'conditional'
data_type: 'ios:health:source_devices_latest'
message:
- 'Device Name: {device_name}'
- 'Manufacturer: {manufacturer}'
- 'Model: {model}'
- 'Hardware Version: {hardware}'
- 'Software/Firmware: {software} / {firmware}'
- 'Local Identifier: {device_local_identifier}'
- 'Synchronization Provenance: {synchronization_provenance}'
- 'Synchronization Identity: {synchronization_identity}'
short_message:
- 'Source Device: {device_name} ({model})'
short_source: 'SQLITE'
source: 'iOS Health database'
---
type: 'conditional'
data_type: 'ios:health:source_devices'
message:
- 'Device Name: {device_name}'
Expand All @@ -175,8 +211,7 @@ message:
- 'Hardware Version: {hardware}'
- 'Software/Firmware: {software} / {firmware}'
- 'Local Identifier: {device_local_identifier}'
- 'Sync Provenance: {sync_provenance}'
- 'Creation Date: {creation_date_str}'
- 'Synchronization Provenance: {synchronization_provenance}'
short_message:
- 'Source Device: {device_name} ({model})'
short_source: 'SQLITE'
Expand All @@ -194,6 +229,43 @@ short_source: 'SQLITE'
source: 'iOS Health database'
---
type: 'conditional'
data_type: 'ios:health:watch_by_sleep_period_latest'
message:
- 'Total Sleep Duration: {total_duration} minutes'
- 'Deep Sleep: {deep_duration_hms} ({deep_percent}%)'
- 'REM Sleep: {rem_duration_hms} ({rem_percent}%)'
- 'Core Sleep: {core_duration_hms} ({core_percent}%)'
- 'Awake: {awake_duration_hms} ({awake_percent}%)'
short_message:
- 'Sleep Period: {total_duration} min (Deep: {deep_percent}%, REM: {rem_percent}%)'
short_source: 'SQLITE'
source: 'iOS Health database'
---
type: 'conditional'
data_type: 'ios:health:watch_by_sleep_period'
message:
- 'Total Time in Bed: {time_in_bed_hms}'
- 'Actual Sleep Percent: {asleep_percent}%'
- 'In Bed Duration: {in_bed_duration_hms} ({in_bed_percent}%)'
- 'Device: {device_name}'
short_message:
- 'Sleep Period: {time_in_bed_hms} (Asleep: {asleep_percent}%)'
short_source: 'SQLITE'
source: 'iOS Health database'
---
type: 'conditional'
data_type: 'ios:health:watch_worn'
message:
- 'Duration Worn: {hours_worn} hours'
- 'Time Off After This Period: {hours_off_before_next} hours'
- 'Start Wearing: {start_time_str}'
- 'Last Worn Time: {last_worn_time_str}'
short_message:
- 'Worn for {hours_worn}h (Then off for {hours_off_before_next}h)'
short_source: 'SQLITE'
source: 'iOS Health database'
---
type: 'conditional'
data_type: 'ios:health:weight'
message:
- 'Weight: {weight:.2f} kg'
Expand Down Expand Up @@ -309,6 +381,123 @@ short_source: 'SQLITE'
source: 'iOS Health database'
---
type: 'conditional'
data_type: 'ios:health:workouts_ios16'
enumeration_helpers:
- input_attribute: 'activity_type'
output_attribute: 'activity_label'
default_value: 'OTHER'
values:
1: "AMERICAN FOOTBALL"
2: "ARCHERY"
3: "AUSTRALIAN FOOTBALL"
4: "BADMINTON"
5: "BASEBALL"
6: "BASKETBALL"
7: "BOWLING"
8: "BOXING"
9: "CLIMBING"
10: "CRICKET"
11: "CROSS TRAINING"
12: "CURLING"
13: "CYCLING"
16: "ELLIPTICAL"
17: "EQUESTRIAN SPORTS"
18: "FENCING"
19: "FISHING"
20: "FUNCTION STRENGTH TRAINING"
21: "GOLF"
22: "GYMNASTICS"
23: "HANDBALL"
24: "HIKING"
25: "HOCKEY"
26: "HUNTING"
27: "LACROSS"
28: "MARTIAL ARTS"
29: "MIND AND BODY"
31: "PADDLE SPORTS"
32: "PLAY"
33: "PREPARATION AND RECOVERY"
34: "RACQUETBALL"
35: "ROWING"
36: "RUGBY"
37: "RUNNING"
38: "SAILING"
39: "SKATING SPORTS"
40: "SNOW SPORTS"
41: "SOCCER"
42: "SOFTBALL"
43: "SQUASH"
44: "STAIRSTEPPER"
45: "SURFING SPORTS"
46: "SWIMMING"
47: "TABLE TENNIS"
48: "TENNIS"
49: "TRACK AND FIELD"
50: "TRADITIONAL STRENGTH TRAINING"
51: "VOLLEYBALL"
52: "WALKING"
53: "WATER FITNESS"
54: "WATER POLO"
55: "WATER SPORTS"
56: "WRESTLING"
57: "YOGA"
58: "BARRE"
59: "CORE TRAINING"
60: "CROSS COUNTRY SKIING"
61: "DOWNHILL SKIING"
62: "FLEXIBILITY"
63: "HIGH INTENSITY INTERVAL TRAINING (HIIT)"
64: "JUMP ROPE"
65: "KICKBOXING"
66: "PILATES"
67: "SNOWBOARDING"
68: "STAIRS"
69: "STEP TRAINING"
70: "WHEELCHAIR WALK PACE"
71: "WHEELCHAIR RUN PACE"
72: "TAI CHI"
73: "MIXED CARDIO"
74: "HAND CYCLING"
75: "DISC SPORTS"
76: "FITNESS GAMING"
77: "DANCE"
78: "SOCIAL DANCE"
79: "PICKLEBALL"
80: "COOLDOWN"
3000: "OTHER"
- input_attribute: 'goal_type'
output_attribute: 'goal_label'
default_value: 'Unknown'
values:
0: "Open"
1: "Distance in meters"
2: "Time in seconds"
3: "Kilocalories"
- input_attribute: 'location_type'
output_attribute: 'location_label'
default_value: 'Unknown'
values:
1: 'Indoor'
2: 'Outdoor'
message:
- 'Activity: {activity_label} ({location_label})'
- 'Workout Goal: {goal_label} ({goal})'
- 'Duration: {workout_duration}'
- 'Distance: {total_distance} km'
- 'Energy: {total_active_energy_kcal} kcal Active / {total_resting_energy_kcal} kcal Resting'
- 'Heart Rate: Avg {avg_heart_rate_bpm} BPM (Min: {min_heart_rate_bpm}, Max: {max_heart_rate_bpm})'
- 'Environment: {temperature_c} °C, {humidity_percent}% Humidity'
- 'Elevation: Min {min_ground_elevation_m}m, Max {max_ground_elevation_m}m'
- 'Location: Lat {latitude}, Lon {longitude}'
- 'Device: {hardware} (Source: {source})'
- 'Timezone: {timezone}'
- 'Added to Health: {added_timestamp_str}'
short_message:
- '{activity_label}: {total_distance} km in {workout_duration}'
short_source: 'SQLITE'
source: 'iOS Health database'
---
type: 'conditional'
data_type: 'ios:health:wrist_temperature'
message:
- 'Wrist temperature: {wrist_temperature} °C'
Expand Down
6 changes: 6 additions & 0 deletions plaso/parsers/sqlite_plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@
from plaso.parsers.sqlite_plugins import ios_accounts
from plaso.parsers.sqlite_plugins import ios_datausage
from plaso.parsers.sqlite_plugins import ios_health
from plaso.parsers.sqlite_plugins import ios_health_all_watch_sleep_latest
from plaso.parsers.sqlite_plugins import ios_health_source_devices_latest
from plaso.parsers.sqlite_plugins import ios_health_watch_by_sleep_period
Comment thread
joachimmetz marked this conversation as resolved.
from plaso.parsers.sqlite_plugins import ios_health_watch_by_sleep_period_latest
from plaso.parsers.sqlite_plugins import ios_health_watch_worn_data
from plaso.parsers.sqlite_plugins import ios_health_workouts_latest
from plaso.parsers.sqlite_plugins import ios_imohdchat
from plaso.parsers.sqlite_plugins import ios_instagram
from plaso.parsers.sqlite_plugins import ios_kik
Expand Down
27 changes: 20 additions & 7 deletions plaso/parsers/sqlite_plugins/ios_health.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class IOSHealthAchievementsEventData(events.EventData):
achievement.
creator_device (int): identifier of the device that created the achievement.
earned_date (str): Date the achievement was earned.
sync_provenance (int): Identifier for the sync provenance.
synchronization_provenance (int): synchronization provenance.
template_unique_name (str): Unique name of the achievement template.
value_canonical_unit (str): Unit of the value (e.g., "count").
value_in_canonical_unit (float): Value of the achievement in canonical units.
Expand All @@ -27,7 +27,7 @@ def __init__(self):
self.creation_time = None
self.creator_device = None
self.earned_date = None
self.sync_provenance = None
self.synchronization_provenance = None
self.template_unique_name = None
self.value_canonical_unit = None
self.value_in_canonical_unit = None
Expand All @@ -37,6 +37,7 @@ class IOSHealthAllWatchSleepEventData(events.EventData):
"""iOS Health all watch sleep event data.

Attributes:
duration (float): duration in seconds.
end_time (dfdatetime.DateTimeValues): date and time the sleep ended.
sleep_state_code (int): sleep state code.
start_time (dfdatetime.DateTimeValues): date and time the sleep started.
Expand All @@ -47,6 +48,7 @@ class IOSHealthAllWatchSleepEventData(events.EventData):
def __init__(self):
"""Initializes event data."""
super().__init__(data_type=self.DATA_TYPE)
self.duration = None
self.end_time = None
self.sleep_state_code = None
self.start_time = None
Expand Down Expand Up @@ -180,7 +182,8 @@ class IOSHealthSourceDevicesEventData(events.EventData):
manufacturer (str): manufacturer of the device.
model (str): model of the device.
software (str): software version of the device.
sync_provenance (int): sync provenance information.
synchronization_identity (int): synchronization identifier.
synchronization_provenance (int): synchronization provenance.
"""

DATA_TYPE = "ios:health:source_devices"
Expand All @@ -196,7 +199,8 @@ def __init__(self):
self.manufacturer = None
self.model = None
self.software = None
self.sync_provenance = None
self.synchronization_identity = None
self.synchronization_provenance = None


class IOSHealthStepsEventData(events.EventData):
Expand Down Expand Up @@ -896,7 +900,7 @@ def _ParseAchievementRow(self, parser_mediator, query, row, **unused_kwargs):
query_hash, row, "value_canonical_unit"
)
event_data.creator_device = self._GetRowValue(query_hash, row, "creator_device")
event_data.sync_provenance = self._GetRowValue(
event_data.synchronization_provenance = self._GetRowValue(
query_hash, row, "sync_provenance"
)
parser_mediator.ProduceEventData(event_data)
Expand All @@ -919,6 +923,16 @@ def _ParseAllWatchSleepSample(self, parser_mediator, query_hash, row):
event_data.sleep_state_code = self._GetRowValue(
query_hash, row, "category_value"
)
if (
event_data.end_time
and event_data.start_time
and event_data.end_time.timestamp is not None
and event_data.start_time.timestamp is not None
):
event_data.duration = (
event_data.end_time.timestamp - event_data.start_time.timestamp
)

parser_mediator.ProduceEventData(event_data)

def _ParseHeadphoneAudioLevelSample(
Expand Down Expand Up @@ -1133,7 +1147,7 @@ def _ParseSourceDevicesRow(self, parser_mediator, query, row, **unused_kwargs):
event_data.manufacturer = self._GetRowValue(query_hash, row, "manufacturer")
event_data.model = self._GetRowValue(query_hash, row, "model")
event_data.software = self._GetRowValue(query_hash, row, "software")
event_data.sync_provenance = self._GetRowValue(
event_data.synchronization_provenance = self._GetRowValue(
query_hash, row, "sync_provenance"
)
parser_mediator.ProduceEventData(event_data)
Expand All @@ -1159,7 +1173,6 @@ def _ParseStepsSample(self, parser_mediator, query_hash, row):
event_data.start_time = self._GetCocoaTimeRowValue(
query_hash, row, "start_date"
)

if (
event_data.end_time
and event_data.start_time
Expand Down
Loading
Loading