Skip to content

Commit f0b6744

Browse files
committed
Merge branch 'refs/heads/dev'
2 parents 335675d + a821b3f commit f0b6744

File tree

20 files changed

+948
-134
lines changed

20 files changed

+948
-134
lines changed

.github/workflows/build.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ jobs:
8181
working-directory: ./macless_haystack
8282
run: |
8383
flutter pub get
84-
flutter build web --release --base-href "/macless-haystack/"
84+
flutter build web --profile --base-href "/macless-haystack/"
8585
- name: Deploy to Github Pages
8686
if: github.ref == 'refs/heads/dev'
8787
uses: JamesIves/github-pages-deploy-action@v4

endpoint/config.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ def getLogLevel():
7171
logLevel = config.get('Settings', 'loglevel', fallback='INFO')
7272
return logging.getLevelName(logLevel)
7373

74-
7574
logging.basicConfig(level=getLogLevel(),
7675
format='%(asctime)s - %(levelname)s - %(message)s')
76+
# Suppress http-log
77+
logging.getLogger('urllib3').setLevel(logging.INFO)

endpoint/mh_endpoint.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ def addCORSHeaders(self):
2828
self.send_header("Access-Control-Allow-Headers", "X-Requested-With")
2929
self.send_header("Access-Control-Allow-Headers", "Content-Type")
3030
self.send_header("Access-Control-Allow-Headers", "Authorization")
31+
self.send_header("Access-Control-Allow-Private-Network","true")
3132

3233
def authenticate(self):
3334
user = config.getEndpointUser()

endpoint/register/apple_cryptography.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,14 @@ def decode_tag(data):
4141
return {'lat': latitude, 'lon': longitude, 'conf': confidence, 'status': status}
4242

4343

44-
def getAuth(regenerate=False, second_factor='sms'):
44+
def getAuth(regenerate=False):
4545
if os.path.exists(config.getConfigFile()) and not regenerate:
4646
with open(config.getConfigFile(), "r") as f:
4747
j = json.load(f)
4848
else:
49+
logger.info('Trying to login')
4950
mobileme = icloud_login_mobileme(
50-
username=config.getUser(), password=config.getPass(), second_factor=second_factor)
51+
username=config.getUser(), password=config.getPass())
5152

5253
logger.debug('Answer from icloud login')
5354
logger.debug(mobileme)
@@ -73,4 +74,4 @@ def getAuth(regenerate=False, second_factor='sms'):
7374
def registerDevice():
7475

7576
logger.info(f'Trying to register new device.')
76-
getAuth(regenerate=True, second_factor='trusted_device' 'sms')
77+
getAuth(regenerate=True)

endpoint/register/pypush_gsa_icloud.py

Lines changed: 36 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@
3232
logger = logging.getLogger()
3333

3434

35-
def icloud_login_mobileme(username='', password='', second_factor='sms'):
35+
def icloud_login_mobileme(username='', password=''):
3636
if not username:
3737
username = input('Apple ID: ')
3838
if not password:
3939
password = getpass('Password: ')
40-
g = gsa_authenticate(username, password, second_factor)
40+
g = gsa_authenticate(username, password)
4141
pet = g["t"]["com.apple.gs.idms.pet"]["token"]
4242
adsid = g["adsid"]
4343

@@ -55,21 +55,24 @@ def icloud_login_mobileme(username='', password='', second_factor='sms'):
5555
}
5656
headers.update(generate_anisette_headers())
5757

58-
r = requests.post(
58+
logger.info("Registering device after login")
59+
resp = requests.post(
5960
"https://setup.icloud.com/setup/iosbuddy/loginDelegates",
6061
auth=(username, pet),
6162
data=data,
6263
headers=headers,
6364
verify=False,
6465
)
65-
return plist.loads(r.content)
66+
response = f"HTTP-Code: {resp.status_code}\n{resp.text}"
67+
logger.debug(response)
68+
return plist.loads(resp.content)
6669

6770

68-
def gsa_authenticate(username, password, second_factor='sms'):
71+
def gsa_authenticate(username, password):
6972
# Password is None as we'll provide it later
7073
usr = srp.User(username, bytes(), hash_alg=srp.SHA256, ng_type=srp.NG_2048)
7174
_, A = usr.start_authentication()
72-
75+
logger.info("Authentication request initialization")
7376
r = gsa_authenticated_request(
7477
{"A2k": A, "ps": ["s2k", "s2k_fo"], "u": username, "o": "init"})
7578

@@ -87,36 +90,38 @@ def gsa_authenticate(username, password, second_factor='sms'):
8790
if M is None:
8891
logger.error("Failed to process challenge")
8992
return
90-
91-
r = gsa_authenticated_request(
93+
logger.info("Authentication request completion")
94+
resp = gsa_authenticated_request(
9295
{"c": r["c"], "M1": M, "u": username, "o": "complete"})
9396

9497
# Make sure that the server's session key matches our session key (and thus that they are not an imposter)
95-
usr.verify_session(r["M2"])
98+
if "M2" not in resp:
99+
logger.error("Error on authentication")
100+
logger.error(resp)
101+
return
102+
usr.verify_session(resp["M2"])
96103
if not usr.authenticated():
97104
logger.error("Failed to verify session")
98105
return
99106

100-
spd = decrypt_cbc(usr, r["spd"])
107+
spd = decrypt_cbc(usr, resp["spd"])
101108
# For some reason plistlib doesn't accept it without the header...
102109
PLISTHEADER = b"""\
103110
<?xml version='1.0' encoding='UTF-8'?>
104111
<!DOCTYPE plist PUBLIC '-//Apple//DTD PLIST 1.0//EN' 'http://www.apple.com/DTDs/PropertyList-1.0.dtd'>
105112
"""
106113
spd = plist.loads(PLISTHEADER + spd)
107114

108-
if "au" in r["Status"] and r["Status"]["au"] in ["trustedDeviceSecondaryAuth", "secondaryAuth"]:
109-
logger.info("2FA required, requesting code")
115+
if "au" in resp["Status"] and resp["Status"]["au"] in ["trustedDeviceSecondaryAuth", "secondaryAuth"]:
116+
logger.info("2FA required, requesting SMS code. (No other 2FA-code will work!)")
110117
# Replace bytes with strings
111118
for k, v in spd.items():
112119
if isinstance(v, bytes):
113120
spd[k] = base64.b64encode(v).decode()
114-
if second_factor == 'sms':
115-
sms_second_factor(spd["adsid"], spd["GsIdmsToken"])
116-
elif second_factor == 'trusted_device':
117-
trusted_second_factor(spd["adsid"], spd["GsIdmsToken"])
121+
sms_second_factor(spd["adsid"], spd["GsIdmsToken"])
122+
118123
return gsa_authenticate(username, password)
119-
elif "au" in r["Status"]:
124+
elif "au" in resp["Status"]:
120125
logger.error(f"Unknown auth value {r['Status']['au']}")
121126
return
122127
else:
@@ -144,6 +149,8 @@ def gsa_authenticated_request(parameters):
144149
verify=False,
145150
timeout=5,
146151
)
152+
response = f"HTTP-Code: {resp.status_code}\n{resp.text}"
153+
logger.debug(response)
147154

148155
return plist.loads(resp.content)["Response"]
149156

@@ -163,10 +170,6 @@ def generate_cpd():
163170

164171

165172
def generate_anisette_headers():
166-
167-
168-
logger.debug(
169-
f'Querying {config.getAnisetteServer()} for an anisette server')
170173
h = json.loads(requests.get(config.getAnisetteServer(), timeout=5).text)
171174
a = {"X-Apple-I-MD": h["X-Apple-I-MD"],
172175
"X-Apple-I-MD-M": h["X-Apple-I-MD-M"]}
@@ -214,48 +217,6 @@ def decrypt_cbc(usr, data):
214217
return padder.update(data) + padder.finalize()
215218

216219

217-
def trusted_second_factor(dsid, idms_token):
218-
identity_token = base64.b64encode(
219-
(dsid + ":" + idms_token).encode()).decode()
220-
221-
headers = {
222-
"Content-Type": "text/x-xml-plist",
223-
"User-Agent": "Xcode",
224-
"Accept": "text/x-xml-plist",
225-
"Accept-Language": "en-us",
226-
"X-Apple-Identity-Token": identity_token,
227-
"X-Apple-App-Info": "com.apple.gs.xcode.auth",
228-
"X-Xcode-Version": "11.2 (11B41)",
229-
"X-Mme-Client-Info": '<MacBookPro18,3> <Mac OS X;13.4.1;22F8> <com.apple.AOSKit/282 (com.apple.dt.Xcode/3594.4.19)>'
230-
}
231-
232-
headers.update(generate_anisette_headers())
233-
234-
# This will trigger the 2FA prompt on trusted devices
235-
# We don't care about the response, it's just some HTML with a form for entering the code
236-
# Easier to just use a text prompt
237-
requests.get(
238-
"https://gsa.apple.com/auth/verify/trusteddevice",
239-
headers=headers,
240-
verify=False,
241-
timeout=10,
242-
)
243-
244-
# Prompt for the 2FA code. It's just a string like '123456', no dashes or spaces
245-
code = getpass("Enter 2FA code: ")
246-
headers["security-code"] = code
247-
248-
# Send the 2FA code to Apple
249-
resp = requests.get(
250-
"https://gsa.apple.com/grandslam/GsService2/validate",
251-
headers=headers,
252-
verify=False,
253-
timeout=10,
254-
)
255-
if resp.ok:
256-
logger.info("2FA successful")
257-
258-
259220
def sms_second_factor(dsid, idms_token):
260221
identity_token = base64.b64encode(
261222
(dsid + ":" + idms_token).encode()).decode()
@@ -290,7 +251,7 @@ def sms_second_factor(dsid, idms_token):
290251
timeout=5
291252
)
292253
# Prompt for the 2FA code. It's just a string like '123456', no dashes or spaces
293-
code = input("Enter 2FA code: ")
254+
code = input("Enter SMS 2FA code: ")
294255

295256
body['securityCode'] = {'code': code}
296257

@@ -302,5 +263,15 @@ def sms_second_factor(dsid, idms_token):
302263
verify=False,
303264
timeout=5,
304265
)
305-
if resp.ok:
266+
response = f"HTTP-Code: {resp.status_code} with {len(resp.text)} bytes"
267+
logger.debug(response)
268+
header_string = "Headers:\n"
269+
for header, value in resp.headers.items():
270+
header_string += f"{header}: {value}\n"
271+
logger.debug(header_string)
272+
# Headers does not include Apple DSID, 2FA failed
273+
if resp.ok and "X-Apple-DSID" in resp.headers:
306274
logger.info("2FA successful")
275+
else:
276+
raise Exception(
277+
"2FA unsuccessful. Maybe wrong code or wrong number. Check your account details.")

0 commit comments

Comments
 (0)