-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathicloud_to_nextcloud.py
135 lines (113 loc) · 4.16 KB
/
icloud_to_nextcloud.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#!/usr/bin/env python3
import configparser
import logging
import sys
import urllib.parse
import requests
from pyicloud import PyiCloudService
from requests.auth import HTTPBasicAuth
###############
# Main script #
###############
def load_config(config_str=None):
"""
Load and parse config from string provided. Defaults to reading from stdin.
"""
if not config_str:
config_str = sys.stdin.read()
config = configparser.ConfigParser()
config.read_string(config_str)
return config
def get_icloud_location(config):
"""
Fetch latest iPhone location from iCloud
"""
email = config['apple']['email']
password = config['apple']['password']
code_2fa = config['apple']['code_2fa']
api = PyiCloudService(email, password=password, cookie_directory=config['apple']['cookie_directory'])
if api.requires_2fa:
print("Two-factor authentication required.")
code = code_2fa
result = api.validate_2fa_code(code)
print("Code validation result: %s" % result)
if not result:
print("Failed to verify security code")
sys.exit(1)
if not api.is_trusted_session:
print("Session is not trusted. Requesting trust...")
result = api.trust_session()
print("Session trust result %s" % result)
if not result:
print("Failed to request trust. You will likely be prompted for the code again in the coming weeks")
elif api.requires_2sa:
import click
print("Two-step 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)
iphone = next(
device
for device in api.devices
if config['apple']['iPhone_name'] in device.status()['name']
)
iphone_location = iphone.location()
iphone_status = iphone.status()
return iphone_location, iphone_status
def store_location_in_nextcloud(config, iphone_location, iphone_status):
"""
Store provided iPhone location to Nextcloud.
"""
if iphone_location is None:
print('Could not retrieved iPhone location. Try again.')
sys.exit(1)
nextcloud_location_args = {
"user_agent": iphone_status['name'],
"lat": iphone_location['latitude'],
"lng": iphone_location['longitude'],
"accuracy": iphone_location['horizontalAccuracy'],
"timestamp": iphone_location['timeStamp'] // 1000,
"altitude": iphone_location['altitude'],
"battery": iphone_status['batteryLevel'],
}
logging.info('Got location data from iCloud: %s.', nextcloud_location_args)
logging.debug(
"curl -X POST -u '%s:%s' '%s'",
config['nextcloud']['user'],
config['nextcloud']['password'],
(
'%s?%s' % (
urllib.parse.urljoin(
config['nextcloud']['server'], '/apps/maps/api/1.0/devices'
),
urllib.parse.urlencode(nextcloud_location_args),
)
),
)
r = requests.post(
urllib.parse.urljoin(
config['nextcloud']['server'], '/apps/maps/api/1.0/devices'
),
params=nextcloud_location_args,
auth=HTTPBasicAuth(
config['nextcloud']['user'], config['nextcloud']['password']
)
)
r.raise_for_status()
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
config = load_config()
iphone_location, iphone_status = get_icloud_location(config)
store_location_in_nextcloud(config, iphone_location, iphone_status)