Skip to content

Commit

Permalink
darwin: split preferences to cf and sc
Browse files Browse the repository at this point in the history
  • Loading branch information
doronz88 committed Feb 16, 2022
1 parent f3e1d8f commit 6ea0d81
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 44 deletions.
55 changes: 55 additions & 0 deletions src/rpcclient/rpcclient/darwin/cfpreferences.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import typing

from rpcclient.exceptions import RpcClientException

kCFPreferencesCurrentUser = 'kCFPreferencesCurrentUser'
kCFPreferencesAnyUser = 'kCFPreferencesAnyUser'
kCFPreferencesCurrentHost = 'kCFPreferencesCurrentHost'
kCFPreferencesAnyHost = 'kCFPreferencesAnyHost'


class CFPreferences:
"""
API to the CFPreferences* functions - preferences managed by cfprefsd.
https://developer.apple.com/documentation/corefoundation/preferences_utilities?language=objc
"""

def __init__(self, client):
"""
:param rpcclient.darwin.client.DarwinClient client:
"""
self._client = client

def copy_key_list(self, application_id: str, username: str = kCFPreferencesCurrentUser,
hostname: str = kCFPreferencesCurrentHost) -> typing.Optional[typing.List[str]]:
application_id = self._client.cf(application_id)
username = self._client.cf(username)
hostname = self._client.cf(hostname)
return self._client.symbols.CFPreferencesCopyKeyList(application_id, username, hostname).py

def copy_value(self, key: str, application_id: str, username: str = kCFPreferencesCurrentUser,
hostname: str = kCFPreferencesCurrentHost) -> typing.Optional[str]:
key = self._client.cf(key)
application_id = self._client.cf(application_id)
username = self._client.cf(username)
hostname = self._client.cf(hostname)
return self._client.symbols.CFPreferencesCopyValue(key, application_id, username, hostname).py

def copy_all_values(self, application_id: str, username: str = kCFPreferencesCurrentUser,
hostname: str = kCFPreferencesCurrentHost) -> typing.Optional[typing.Mapping]:
result = {}
key_list = self.copy_key_list(application_id, username, hostname)
if not key_list:
raise RpcClientException(f'failed to get key list for: {application_id}/{username}/{hostname}')
for k in key_list:
result[k] = self.copy_value(k, application_id, username, hostname)
return result

def set_value(self, key: str, value: str, application_id: str, username: str = kCFPreferencesCurrentUser,
hostname: str = kCFPreferencesCurrentHost):
key = self._client.cf(key)
value = self._client.cf(value)
application_id = self._client.cf(application_id)
username = self._client.cf(username)
hostname = self._client.cf(hostname)
self._client.symbols.CFPreferencesSetValue(key, value, application_id, username, hostname)
13 changes: 7 additions & 6 deletions src/rpcclient/rpcclient/darwin/client.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
from collections import namedtuple
from functools import lru_cache
import struct
import typing
from collections import namedtuple
from functools import lru_cache

from cached_property import cached_property

from rpcclient.client import Client
from rpcclient.darwin import objective_c_class
from rpcclient.darwin.consts import kCFNumberSInt64Type, kCFNumberDoubleType
from rpcclient.darwin.fs import DarwinFs
from rpcclient.darwin.media import DarwinMedia
from rpcclient.darwin.network import DarwinNetwork
from rpcclient.darwin.objective_c_symbol import ObjectiveCSymbol
from rpcclient.darwin.processes import DarwinProcesses
from rpcclient.darwin.preferences import Preferences
from rpcclient.exceptions import RpcClientException
from rpcclient.darwin.processes import DarwinProcesses
from rpcclient.darwin.structs import utsname
from rpcclient.darwin.consts import kCFNumberSInt64Type, kCFNumberDoubleType
from rpcclient.darwin.symbol import DarwinSymbol
from rpcclient.exceptions import RpcClientException

IsaMagic = namedtuple('IsaMagic', 'mask value')
ISA_MAGICS = [
Expand Down Expand Up @@ -52,7 +52,7 @@ def __init__(self, sock, sysname: str, hostname: str, port: int = None):
if self.uname.machine != 'x86_64':
self.inode64 = True
self.fs = DarwinFs(self)
self.prefs = Preferences(self)
self.preferences = Preferences(self)
self.processes = DarwinProcesses(self)
self.media = DarwinMedia(self)
self.network = DarwinNetwork(self)
Expand All @@ -75,6 +75,7 @@ def is_idevice(self):
return self.uname.machine.startswith('i')

def set_airplane_mode(self, mode: bool):
""" set whether the device should enter airplane mode (turns off baseband, bt, etc...) """
preferences = self.symbols.objc_getClass('RadiosPreferences').objc_call('new')
preferences.objc_call('setAirplaneMode:', mode)
preferences.objc_call('synchronize')
Expand Down
44 changes: 6 additions & 38 deletions src/rpcclient/rpcclient/darwin/preferences.py
Original file line number Diff line number Diff line change
@@ -1,45 +1,13 @@
import typing

kCFPreferencesCurrentUser = 'kCFPreferencesCurrentUser'
kCFPreferencesAnyUser = 'kCFPreferencesAnyUser'
kCFPreferencesCurrentHost = 'kCFPreferencesCurrentHost'
kCFPreferencesAnyHost = 'kCFPreferencesAnyHost'
from rpcclient.darwin.cfpreferences import CFPreferences
from rpcclient.darwin.scpreferences import SCPreferences


class Preferences:
""" Preferences utils """

def __init__(self, client):
"""
:param rpcclient.darwin.client.DarwinClient client:
"""
self._client = client

def copy_key_list(self, application_id: str, username: str = kCFPreferencesCurrentUser,
hostname: str = kCFPreferencesCurrentHost) -> typing.Optional[typing.List[str]]:
application_id = self._client.cf(application_id)
username = self._client.cf(username)
hostname = self._client.cf(hostname)
return self._client.symbols.CFPreferencesCopyKeyList(application_id, username, hostname).py

def copy_value(self, key: str, application_id: str, username: str = kCFPreferencesCurrentUser,
hostname: str = kCFPreferencesCurrentHost) -> typing.Optional[str]:
key = self._client.cf(key)
application_id = self._client.cf(application_id)
username = self._client.cf(username)
hostname = self._client.cf(hostname)
return self._client.symbols.CFPreferencesCopyValue(key, application_id, username, hostname).py

def copy_all_values(self, application_id: str, username: str = kCFPreferencesCurrentUser,
hostname: str = kCFPreferencesCurrentHost) -> typing.Optional[typing.Mapping]:
result = {}
for k in self.copy_key_list(application_id, username, hostname):
result[k] = self.copy_value(k, application_id, username, hostname)
return result

def set_value(self, key: str, value: str, application_id: str, username: str = kCFPreferencesCurrentUser,
hostname: str = kCFPreferencesCurrentHost):
key = self._client.cf(key)
value = self._client.cf(value)
application_id = self._client.cf(application_id)
username = self._client.cf(username)
hostname = self._client.cf(hostname)
self._client.symbols.CFPreferencesSetValue(key, value, application_id, username, hostname)
self.cf = CFPreferences(client)
self.sc = SCPreferences(client)
76 changes: 76 additions & 0 deletions src/rpcclient/rpcclient/darwin/scpreferences.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import typing

from rpcclient.exceptions import RpcClientException


class SCPreferencesObject:
def __init__(self, client, ref):
self._client = client
self._ref = ref

def __enter__(self):
return self

def __exit__(self, exc_type, exc_val, exc_tb):
try:
yield
finally:
self.release()

@property
def keys(self) -> typing.List[str]:
return self._client.symbols.SCPreferencesCopyKeyList(self._ref).py

def set(self, key: str, value):
if not self._client.symbols.SCPreferencesSetValue(self._ref, self._client.cf(key), self._client.cf(value)):
raise RpcClientException(f'SCPreferencesSetValue failed to set: {key}')
self._commit()

def remove(self, key: str):
if not self._client.symbols.SCPreferencesRemoveValue(self._ref, self._client.cf(key)):
raise RpcClientException(f'SCPreferencesRemoveValue failed to remove: {key}')
self._commit()

def get(self, key: str):
return self._client.symbols.SCPreferencesGetValue(self._ref, self._client.cf(key)).py

def to_dict(self) -> typing.Mapping:
result = {}
for k in self.keys:
result[k] = self.get(k)
return result

def release(self):
self._client.CFRelase(self._ref)

def _commit(self):
if not self._client.symbols.SCPreferencesCommitChanges(self._ref):
raise RpcClientException('SCPreferencesCommitChanges failed')
self._client.symbols.SCPreferencesSynchronize(self._ref)


class SCPreferences:
"""
API to the SCPreferences* functions - preferences managed by SystemConfiguration framework.
https://developer.apple.com/documentation/systemconfiguration/scpreferences?language=objc
"""

def __init__(self, client):
"""
:param rpcclient.darwin.client.DarwinClient client:
"""
self._client = client

def get_preferences_object(self, preferences_id: str) -> SCPreferencesObject:
ref = self._client.symbols.SCPreferencesCreate(0, self._client.cf('rpcserver'), self._client.cf(preferences_id))
if not ref:
raise RpcClientException(f'SCPreferencesCreate failed for: {preferences_id}')
return SCPreferencesObject(self._client, ref)

def get_key_list(self, preferences_id: str) -> typing.List[str]:
with self.get_preferences_object(preferences_id) as o:
return o.keys

def get_dict(self, preferences_id: str):
with self.get_preferences_object(preferences_id) as o:
return o.to_dict()

0 comments on commit 6ea0d81

Please sign in to comment.