Add debugging example to CODE_SAMPLES.md (#295)

Add an example invocation to CODE_SAMPLES that would allow for
MITM interception as well as debug prints to the console.

Drive-By: blacken the code samples.
Drive-By: Make code samples compliant with python3 (print->print())
Fixes: #270
This commit is contained in:
Andreas Thienemann 2020-08-13 13:46:55 +02:00 committed by GitHub
parent 0401299dbb
commit 4075c41ecc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -25,56 +25,55 @@ import datetime
from pyicloud import PyiCloudService from pyicloud import PyiCloudService
print('Setup Time Zone') print("Setup Time Zone")
time.strftime('%X %x %Z') time.strftime("%X %x %Z")
os.environ['TZ'] = 'America/New_York' os.environ["TZ"] = "America/New_York"
print("Py iCloud Services")
print('Py iCloud Services') api = PyiCloudService("your@me.com", "password")
api = PyiCloudService('your@me.com', 'password')
if api.requires_2fa: if api.requires_2fa:
print "Two-factor authentication required. Your trusted devices are:" print("Two-factor authentication required. Your trusted devices are:")
devices = api.trusted_devices devices = api.trusted_devices
for i, device in enumerate(devices): for i, device in enumerate(devices):
print " %s: %s" % (i, device.get('deviceName', "SMS to %s" % print(
device.get('phoneNumber'))) " %s: %s"
% (i, device.get("deviceName", "SMS to %s" % device.get("phoneNumber")))
)
device = click.prompt('Which device would you like to use?', default=0) device = click.prompt("Which device would you like to use?", default=0)
device = devices[device] device = devices[device]
if not api.send_verification_code(device): if not api.send_verification_code(device):
print "Failed to send verification code" print("Failed to send verification code")
sys.exit(1) sys.exit(1)
code = click.prompt('Please enter validation code') code = click.prompt("Please enter validation code")
if not api.validate_verification_code(device, code): if not api.validate_verification_code(device, code):
print "Failed to verify verification code" print("Failed to verify verification code")
sys.exit(1) sys.exit(1)
# #
# Devices # Devices
# #
print('Devices') print("Devices")
print(api.devices) print(api.devices)
print(api.devices[0]) print(api.devices[0])
print(api.iphone) print(api.iphone)
# #
# Location # Location
# #
print('Location') print("Location")
print(api.iphone.location()) print(api.iphone.location())
# #
# Status # Status
# #
print('Status') print("Status")
print(api.iphone.status()) print(api.iphone.status())
# #
@ -86,7 +85,7 @@ print(api.iphone.status())
# #
# Events # Events
# #
print('Events') print("Events")
print(api.calendar.events()) print(api.calendar.events())
from_dt = datetime.date(2018, 1, 1) from_dt = datetime.date(2018, 1, 1)
to_dt = datetime.date(2018, 1, 31) to_dt = datetime.date(2018, 1, 31)
@ -96,9 +95,9 @@ print(api.calendar.events(from_dt, to_dt))
# ======== # ========
# Contacts # Contacts
# ======== # ========
print('Contacts') print("Contacts")
for c in api.contacts.all(): for c in api.contacts.all():
print c.get('firstName'), c.get('phones') print(c.get("firstName"), c.get("phones"))
# ======================= # =======================
@ -107,6 +106,118 @@ for c in api.contacts.all():
# You can access documents stored in your iCloud account by using the # You can access documents stored in your iCloud account by using the
# ``files`` property's ``dir`` method: # ``files`` property's ``dir`` method:
print('File Storage') print("File Storage")
print(api.files.dir()) print(api.files.dir())
``` ```
## From [@ixs](https://github.com/ixs)
### Debug build of pyicloud
This example allows to use tools like mitmproxy, fiddler, charles or similiar
things to debug the data sent on the wire.
In addition, the underlying requests module and the http.client are asked, to
output all data sent and received to stdout.
This uses code taken from [How do I disable the security certificate check in Python requests](https://stackoverflow.com/questions/15445981/how-do-i-disable-the-security-certificate-check-in-python-requests)
and [Log all requests from the python-requests module](https://stackoverflow.com/questions/16337511/log-all-requests-from-the-python-requests-module)
```python
#!/usr/bin/env python3
import contextlib
import http.client
import logging
import requests
import warnings
from pprint import pprint
from pyicloud import PyiCloudService
from urllib3.exceptions import InsecureRequestWarning
# Handle certificate warnings by ignoring them
old_merge_environment_settings = requests.Session.merge_environment_settings
@contextlib.contextmanager
def no_ssl_verification():
opened_adapters = set()
def merge_environment_settings(self, url, proxies, stream, verify, cert):
# Verification happens only once per connection so we need to close
# all the opened adapters once we're done. Otherwise, the effects of
# verify=False persist beyond the end of this context manager.
opened_adapters.add(self.get_adapter(url))
settings = old_merge_environment_settings(
self, url, proxies, stream, verify, cert
)
settings["verify"] = False
return settings
requests.Session.merge_environment_settings = merge_environment_settings
try:
with warnings.catch_warnings():
warnings.simplefilter("ignore", InsecureRequestWarning)
yield
finally:
requests.Session.merge_environment_settings = old_merge_environment_settings
for adapter in opened_adapters:
try:
adapter.close()
except:
pass
# Monkeypatch the http client for full debugging output
httpclient_logger = logging.getLogger("http.client")
def httpclient_logging_patch(level=logging.DEBUG):
"""Enable HTTPConnection debug logging to the logging framework"""
def httpclient_log(*args):
httpclient_logger.log(level, " ".join(args))
# mask the print() built-in in the http.client module to use
# logging instead
http.client.print = httpclient_log
# enable debugging
http.client.HTTPConnection.debuglevel = 1
# Enable general debug logging
logging.basicConfig(level=logging.DEBUG)
httpclient_logging_patch()
api = PyiCloudService(username, password)
if api.requires_2sa:
print("Two-factor authentication required. Your trusted devices are:")
devices = api.trusted_devices
for i, device in enumerate(devices):
print(
" %s: %s"
% (i, device.get("deviceName", "SMS to %s") % device.get("phoneNumber"))
)
device = click.prompt("Which device would you like to use?", default=0)
device = devices[device]
if not api.send_verification_code(device):
print("Failed to send verification code")
sys.exit(1)
code = click.prompt("Please enter validation code")
if not api.validate_verification_code(device, code):
print("Failed to verify verification code")
sys.exit(1)
# This request will not fail, even if using intercepting proxies.
with no_ssl_verification():
pprint(api.account)
```