mirror of
https://github.com/malmeloo/FindMy.py.git
synced 2026-04-17 21:53:57 +02:00
Merge pull request #125 from pajowu/pajowu/aligment
Add option to align FindMyAccessories key generation
This commit is contained in:
@@ -4,6 +4,7 @@ Example showing how to fetch locations of an AirTag, or any other FindMy accesso
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import sys
|
||||
from pathlib import Path
|
||||
@@ -30,10 +31,15 @@ ANISETTE_LIBS_PATH = "ani_libs.bin"
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
|
||||
def main(plist_path: str) -> int:
|
||||
def main(plist_path: Path, alignment_plist_path: Path | None) -> int:
|
||||
# Step 0: create an accessory key generator
|
||||
with Path(plist_path).open("rb") as f:
|
||||
airtag = FindMyAccessory.from_plist(f)
|
||||
with plist_path.open("rb") as f:
|
||||
f2 = alignment_plist_path.open("rb") if alignment_plist_path else None
|
||||
|
||||
airtag = FindMyAccessory.from_plist(f, f2)
|
||||
|
||||
if f2:
|
||||
f2.close()
|
||||
|
||||
# Step 1: log into an Apple account
|
||||
print("Logging into account")
|
||||
@@ -56,10 +62,9 @@ def main(plist_path: str) -> int:
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print(f"Usage: {sys.argv[0]} <path to accessory plist>", file=sys.stderr)
|
||||
print(file=sys.stderr)
|
||||
print("The plist file should be dumped from MacOS's FindMy app.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("plist_path", type=Path)
|
||||
parser.add_argument("--alignment_plist_path", default=None, type=Path)
|
||||
args = parser.parse_args()
|
||||
|
||||
sys.exit(main(sys.argv[1]))
|
||||
sys.exit(main(args.plist_path, args.alignment_plist_path))
|
||||
|
||||
@@ -95,6 +95,8 @@ class FindMyAccessory(RollingKeyPairSource, Serializable[FindMyAccessoryMapping]
|
||||
name: str | None = None,
|
||||
model: str | None = None,
|
||||
identifier: str | None = None,
|
||||
alignment_date: datetime | None = None,
|
||||
alignment_index: int | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize a FindMyAccessory. These values are usually obtained during pairing.
|
||||
@@ -116,6 +118,14 @@ class FindMyAccessory(RollingKeyPairSource, Serializable[FindMyAccessoryMapping]
|
||||
self._name = name
|
||||
self._model = model
|
||||
self._identifier = identifier
|
||||
self._alignment_date = alignment_date if alignment_date is not None else paired_at
|
||||
self._alignment_index = alignment_index if alignment_index is not None else 0
|
||||
if self._alignment_date.tzinfo is None:
|
||||
self._alignment_date = self._alignment_date.astimezone()
|
||||
logger.warning(
|
||||
"Alignment datetime is timezone-naive. Assuming system tz: %s.",
|
||||
self._alignment_date.tzname(),
|
||||
)
|
||||
|
||||
@property
|
||||
def master_key(self) -> bytes:
|
||||
@@ -173,25 +183,27 @@ class FindMyAccessory(RollingKeyPairSource, Serializable[FindMyAccessoryMapping]
|
||||
secondary_offset = 0
|
||||
|
||||
if isinstance(ind, datetime):
|
||||
# number of 15-minute slots since pairing time
|
||||
ind = (
|
||||
# number of 15-minute slots since alignment
|
||||
slots_since_alignment = (
|
||||
int(
|
||||
(ind - self._paired_at).total_seconds() / (15 * 60),
|
||||
(ind - self._alignment_date).total_seconds() / (15 * 60),
|
||||
)
|
||||
+ 1
|
||||
)
|
||||
ind = self._alignment_index + slots_since_alignment
|
||||
|
||||
# number of slots until first 4 am
|
||||
first_rollover = self._paired_at.astimezone().replace(
|
||||
first_rollover = self._alignment_date.astimezone().replace(
|
||||
hour=4,
|
||||
minute=0,
|
||||
second=0,
|
||||
microsecond=0,
|
||||
)
|
||||
if first_rollover < self._paired_at: # we rolled backwards, so increment the day
|
||||
if first_rollover < self._alignment_date: # we rolled backwards, so increment the day
|
||||
first_rollover += timedelta(days=1)
|
||||
secondary_offset = (
|
||||
int(
|
||||
(first_rollover - self._paired_at).total_seconds() / (15 * 60),
|
||||
(first_rollover - self._alignment_date).total_seconds() / (15 * 60),
|
||||
)
|
||||
+ 1
|
||||
)
|
||||
@@ -213,6 +225,7 @@ class FindMyAccessory(RollingKeyPairSource, Serializable[FindMyAccessoryMapping]
|
||||
def from_plist(
|
||||
cls,
|
||||
plist: str | Path | dict | bytes | IO[bytes],
|
||||
key_alignment_plist: IO[bytes] | None = None,
|
||||
*,
|
||||
name: str | None = None,
|
||||
) -> FindMyAccessory:
|
||||
@@ -247,6 +260,16 @@ class FindMyAccessory(RollingKeyPairSource, Serializable[FindMyAccessoryMapping]
|
||||
model = device_data["model"]
|
||||
identifier = device_data["identifier"]
|
||||
|
||||
alignment_date = None
|
||||
index = None
|
||||
if key_alignment_plist:
|
||||
alignment_data = plistlib.load(key_alignment_plist)
|
||||
|
||||
alignment_date = alignment_data["lastIndexObservationDate"].replace(
|
||||
tzinfo=timezone.utc,
|
||||
)
|
||||
index = alignment_data["lastIndexObserved"]
|
||||
|
||||
return cls(
|
||||
master_key=master_key,
|
||||
skn=skn,
|
||||
@@ -255,6 +278,8 @@ class FindMyAccessory(RollingKeyPairSource, Serializable[FindMyAccessoryMapping]
|
||||
name=name,
|
||||
model=model,
|
||||
identifier=identifier,
|
||||
alignment_date=alignment_date,
|
||||
alignment_index=index,
|
||||
)
|
||||
|
||||
@override
|
||||
|
||||
Reference in New Issue
Block a user