From a6d421342dc64d836347cb5ee699532f937fafe7 Mon Sep 17 00:00:00 2001 From: doron zarhi Date: Mon, 28 Feb 2022 16:44:39 +0200 Subject: [PATCH] darwin: add datetime serialization support --- src/rpcclient/rpcclient/darwin/client.py | 16 +++++++++++++++- src/rpcclient/rpcclient/darwin/symbol.py | 6 +++--- .../tests/test_core_foundation_types.py | 2 ++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/rpcclient/rpcclient/darwin/client.py b/src/rpcclient/rpcclient/darwin/client.py index a6387ab5..a4829504 100644 --- a/src/rpcclient/rpcclient/darwin/client.py +++ b/src/rpcclient/rpcclient/darwin/client.py @@ -1,3 +1,4 @@ +import datetime import struct import typing from collections import namedtuple @@ -101,7 +102,20 @@ def cf(self, o: object): return self.symbols.CFStringCreateWithCString(kCFAllocatorDefault, o, CFStringEncoding.kCFStringEncodingMacRoman) elif isinstance(o, bytes): - return self.symbols.CFDataCreate(0, o, len(o)) + return self.symbols.CFDataCreate(kCFAllocatorDefault, o, len(o)) + elif isinstance(o, datetime.datetime): + comps = self.symbols.objc_getClass('NSDateComponents').objc_call('new') + comps.objc_call('setDay:', o.day) + comps.objc_call('setMonth:', o.month) + comps.objc_call('setYear:', o.year) + comps.objc_call('setHour:', o.hour) + comps.objc_call('setMinute:', o.minute) + comps.objc_call('setSecond:', o.second) + comps.objc_call('setTimeZone:', + self.symbols.objc_getClass('NSTimeZone').objc_call('timeZoneWithAbbreviation:', + self.cf('UTC'))) + return self.symbols.objc_getClass('NSCalendar').objc_call('currentCalendar') \ + .objc_call('dateFromComponents:', comps) elif isinstance(o, bool): if o: return self.symbols.kCFBooleanTrue[0] diff --git a/src/rpcclient/rpcclient/darwin/symbol.py b/src/rpcclient/rpcclient/darwin/symbol.py index 004cc827..482fa879 100644 --- a/src/rpcclient/rpcclient/darwin/symbol.py +++ b/src/rpcclient/rpcclient/darwin/symbol.py @@ -1,5 +1,5 @@ +import datetime import struct -import time from typing import List, Mapping from rpcclient.darwin.consts import kCFNumberSInt64Type, kCFNumberDoubleType, CFStringEncoding @@ -52,8 +52,8 @@ def _decode_cfnumber(self) -> int: raise CfSerializationError(f'failed to deserialize int: {self}') return int(buf[0]) - def _decode_cfdate(self) -> time.struct_time: - return time.strptime(self.cfdesc, '%Y-%m-%d %H:%M:%S %z') + def _decode_cfdate(self) -> datetime.datetime: + return datetime.datetime.strptime(self.cfdesc, '%Y-%m-%d %H:%M:%S %z') def _decode_cfdata(self) -> bytes: count = self._client.symbols.CFDataGetLength(self) diff --git a/src/rpcclient/tests/test_core_foundation_types.py b/src/rpcclient/tests/test_core_foundation_types.py index 3e184cbf..3482add2 100644 --- a/src/rpcclient/tests/test_core_foundation_types.py +++ b/src/rpcclient/tests/test_core_foundation_types.py @@ -1,3 +1,4 @@ +import datetime import pytest @@ -5,6 +6,7 @@ None, True, False, + datetime.datetime(1967, 5, 4, 3, 2, 1, tzinfo=datetime.timezone.utc), 'string', b'bytes', 123,