"""Plist parser plugin for MacOS software update plist files."""
from plaso.containers import events
from plaso.parsers import plist
from plaso.parsers.plist_plugins import interface
[docs]
class MacOSSoftwareUpdateEventData(events.EventData):
"""MacOS software update event data.
Attributes:
full_update_time (dfdatetime.DateTimeValues): date and time of last
full MacOS software update.
recommended_updates (list[str]): recommended updates.
system_version (str): operating system version.
update_time (dfdatetime.DateTimeValues): date and time of last
MacOS software update.
"""
DATA_TYPE = "macos:software_updata:entry"
[docs]
def __init__(self):
"""Initializes event data."""
super().__init__(data_type=self.DATA_TYPE)
self.full_update_time = None
self.recommended_updates = None
self.system_version = None
self.update_time = None
[docs]
class MacOSSoftwareUpdatePlistPlugin(interface.PlistPlugin):
"""Plist parser plugin for MacOS software update plist files.
Further details about the extracted fields:
LastFullSuccessfulDate:
timestamp when MacOS was full update.
LastSuccessfulDate:
timestamp when MacOS was partially update.
"""
NAME = "macos_software_update"
DATA_FORMAT = "MacOS software update plist file"
PLIST_PATH_FILTERS = frozenset(
[interface.PlistPathFilter("com.apple.SoftwareUpdate.plist")]
)
PLIST_KEYS = frozenset(
[
"LastFullSuccessfulDate",
"LastSuccessfulDate",
"LastAttemptSystemVersion",
"LastUpdatesAvailable",
"LastRecommendedUpdatesAvailable",
"RecommendedUpdates",
]
)
# pylint: disable=arguments-differ
def _ParsePlist(self, parser_mediator, match=None, **unused_kwargs):
"""Extracts relevant MacOS update entries.
Args:
parser_mediator (ParserMediator): mediates interactions between parsers
and other components, such as storage and dfVFS.
match (Optional[dict[str: object]]): keys extracted from PLIST_KEYS.
"""
last_full_successful_date = match.get("LastFullSuccessfulDate")
last_successful_date = match.get("LastSuccessfulDate")
recommended_updates = []
if match.get("LastUpdatesAvailable"):
for update_property in match.get("RecommendedUpdates", []):
identifier = update_property.get("Identifier")
product_key = update_property.get("Product Key")
recommended_updates.append(f"{identifier:s} ({product_key:s})")
event_data = MacOSSoftwareUpdateEventData()
event_data.full_update_time = self._GetDateTimeValueFromPlistKey(
match, "LastFullSuccessfulDate"
)
event_data.recommended_updates = recommended_updates or None
event_data.system_version = match.get("LastAttemptSystemVersion")
# Only set update_time if it differs from full_update_time.
if last_successful_date and last_successful_date != last_full_successful_date:
event_data.update_time = self._GetDateTimeValueFromPlistKey(
match, "LastSuccessfulDate"
)
parser_mediator.ProduceEventData(event_data)
plist.PlistParser.RegisterPlugin(MacOSSoftwareUpdatePlistPlugin)