mirror of
https://github.com/malmeloo/FindMy.py.git
synced 2026-04-17 21:53:57 +02:00
accessory: Integrate .plist reading into library
This commit is contained in:
@@ -3,13 +3,11 @@ Example showing how to fetch locations of an AirTag, or any other FindMy accesso
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import plistlib
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
|
||||
from _login import get_account_sync
|
||||
|
||||
from findmy import FindMyAccessory, KeyPair
|
||||
from findmy import FindMyAccessory
|
||||
from findmy.reports import RemoteAnisetteProvider
|
||||
|
||||
# URL to (public or local) anisette server
|
||||
@@ -18,37 +16,11 @@ ANISETTE_SERVER = "http://localhost:6969"
|
||||
# Path to a .plist dumped from the Find My app.
|
||||
PLIST_PATH = Path("airtag.plist")
|
||||
|
||||
# == The variables below are auto-filled from the plist!! ==
|
||||
|
||||
with PLIST_PATH.open("rb") as f:
|
||||
device_data = plistlib.load(f)
|
||||
|
||||
# PRIVATE master key. 28 (?) bytes.
|
||||
MASTER_KEY = device_data["privateKey"]["key"]["data"][-28:]
|
||||
|
||||
# "Primary" shared secret. 32 bytes.
|
||||
SKN = device_data["sharedSecret"]["key"]["data"]
|
||||
|
||||
# "Secondary" shared secret. 32 bytes.
|
||||
SKS = device_data["secondarySharedSecret"]["key"]["data"]
|
||||
|
||||
# "Paired at" timestamp (UTC)
|
||||
PAIRED_AT = device_data["pairingDate"].replace(tzinfo=timezone.utc)
|
||||
|
||||
|
||||
def _gen_keys(airtag: FindMyAccessory, _from: datetime, to: datetime) -> set[KeyPair]:
|
||||
keys = set()
|
||||
while _from < to:
|
||||
keys.update(airtag.keys_at(_from))
|
||||
|
||||
_from += timedelta(minutes=15)
|
||||
|
||||
return keys
|
||||
|
||||
|
||||
def main() -> None:
|
||||
# Step 0: create an accessory key generator
|
||||
airtag = FindMyAccessory(MASTER_KEY, SKN, SKS, PAIRED_AT)
|
||||
with PLIST_PATH.open("rb") as f:
|
||||
airtag = FindMyAccessory.from_plist(f)
|
||||
|
||||
# Step 1: log into an Apple account
|
||||
print("Logging into account")
|
||||
|
||||
@@ -6,9 +6,10 @@ Accessories could be anything ranging from AirTags to iPhones.
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import plistlib
|
||||
from abc import ABC, abstractmethod
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Generator, overload
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from typing import IO, Generator, overload
|
||||
|
||||
from typing_extensions import override
|
||||
|
||||
@@ -143,6 +144,30 @@ class FindMyAccessory(RollingKeyPairSource):
|
||||
|
||||
return possible_keys
|
||||
|
||||
@classmethod
|
||||
def from_plist(cls, plist: IO[bytes]) -> FindMyAccessory:
|
||||
"""Create a FindMyAccessory from a .plist file dumped from the FindMy app."""
|
||||
device_data = plistlib.load(plist)
|
||||
|
||||
# PRIVATE master key. 28 (?) bytes.
|
||||
master_key = device_data["privateKey"]["key"]["data"][-28:]
|
||||
|
||||
# "Primary" shared secret. 32 bytes.
|
||||
skn = device_data["sharedSecret"]["key"]["data"]
|
||||
|
||||
# "Secondary" shared secret. 32 bytes.
|
||||
if "secondarySharedSecret" in device_data:
|
||||
# AirTag
|
||||
sks = device_data["secondarySharedSecret"]["key"]["data"]
|
||||
else:
|
||||
# iDevice
|
||||
sks = device_data["secureLocationsSharedSecret"]["key"]["data"]
|
||||
|
||||
# "Paired at" timestamp (UTC)
|
||||
paired_at = device_data["pairingDate"].replace(tzinfo=timezone.utc)
|
||||
|
||||
return cls(master_key, skn, sks, paired_at)
|
||||
|
||||
|
||||
class AccessoryKeyGenerator(KeyGenerator[KeyPair]):
|
||||
"""KeyPair generator. Uses the same algorithm internally as FindMy accessories do."""
|
||||
|
||||
Reference in New Issue
Block a user