findmy.reports ============== .. py:module:: findmy.reports .. autoapi-nested-parse:: Code related to fetching location reports. Submodules ---------- .. toctree:: :maxdepth: 1 /autoapi/findmy/reports/account/index /autoapi/findmy/reports/anisette/index /autoapi/findmy/reports/reports/index /autoapi/findmy/reports/state/index /autoapi/findmy/reports/twofactor/index Classes ------- .. autoapisummary:: findmy.reports.AppleAccount findmy.reports.AsyncAppleAccount findmy.reports.BaseAnisetteProvider findmy.reports.RemoteAnisetteProvider findmy.reports.LoginState findmy.reports.SmsSecondFactorMethod findmy.reports.TrustedDeviceSecondFactorMethod Package Contents ---------------- .. py:class:: AppleAccount(anisette: findmy.reports.anisette.BaseAnisetteProvider, user_id: str | None = None, device_id: str | None = None) Bases: :py:obj:`BaseAppleAccount` A sync implementation of `BaseappleAccount`. Uses `AsyncappleAccount` internally. .. py:method:: close() -> None :async: See `AsyncAppleAccount.close`. .. py:property:: login_state :type: findmy.reports.state.LoginState See `AsyncAppleAccount.login_state`. .. py:property:: account_name :type: str | None See `AsyncAppleAccount.login_state`. .. py:property:: first_name :type: str | None See `AsyncAppleAccount.first_name`. .. py:property:: last_name :type: str | None See `AsyncAppleAccount.last_name`. .. py:method:: export() -> dict See `AsyncAppleAccount.export`. .. py:method:: restore(data: dict) -> None See `AsyncAppleAccount.restore`. .. py:method:: login(username: str, password: str) -> findmy.reports.state.LoginState See `AsyncAppleAccount.login`. .. py:method:: get_2fa_methods() -> Sequence[findmy.reports.twofactor.SyncSecondFactorMethod] See `AsyncAppleAccount.get_2fa_methods`. .. py:method:: sms_2fa_request(phone_number_id: int) -> None See `AsyncAppleAccount.sms_2fa_request`. .. py:method:: sms_2fa_submit(phone_number_id: int, code: str) -> findmy.reports.state.LoginState See `AsyncAppleAccount.sms_2fa_submit`. .. py:method:: td_2fa_request() -> None See `AsyncAppleAccount.td_2fa_request`. .. py:method:: td_2fa_submit(code: str) -> findmy.reports.state.LoginState See `AsyncAppleAccount.td_2fa_submit`. .. py:method:: fetch_reports(keys: findmy.keys.HasHashedPublicKey, date_from: datetime.datetime, date_to: datetime.datetime | None) -> list[findmy.reports.reports.LocationReport] fetch_reports(keys: Sequence[findmy.keys.HasHashedPublicKey], date_from: datetime.datetime, date_to: datetime.datetime | None) -> dict[findmy.keys.HasHashedPublicKey, list[findmy.reports.reports.LocationReport]] fetch_reports(keys: findmy.accessory.RollingKeyPairSource, date_from: datetime.datetime, date_to: datetime.datetime | None) -> list[findmy.reports.reports.LocationReport] See `AsyncAppleAccount.fetch_reports`. .. py:method:: fetch_last_reports(keys: findmy.keys.HasHashedPublicKey, hours: int = 7 * 24) -> list[findmy.reports.reports.LocationReport] fetch_last_reports(keys: Sequence[findmy.keys.HasHashedPublicKey], hours: int = 7 * 24) -> dict[findmy.keys.HasHashedPublicKey, list[findmy.reports.reports.LocationReport]] fetch_last_reports(keys: findmy.accessory.RollingKeyPairSource, hours: int = 7 * 24) -> list[findmy.reports.reports.LocationReport] See `AsyncAppleAccount.fetch_last_reports`. .. py:method:: get_anisette_headers(with_client_info: bool = False, serial: str = '0') -> dict[str, str] See `AsyncAppleAccount.get_anisette_headers`. .. py:class:: AsyncAppleAccount(anisette: findmy.reports.anisette.BaseAnisetteProvider, user_id: str | None = None, device_id: str | None = None) Bases: :py:obj:`BaseAppleAccount` An async implementation of `BaseAppleAccount`. .. py:property:: login_state :type: findmy.reports.state.LoginState See `BaseAppleAccount.login_state`. .. py:property:: account_name :type: str | None See `BaseAppleAccount.account_name`. .. py:property:: first_name :type: str | None See `BaseAppleAccount.first_name`. .. py:property:: last_name :type: str | None See `BaseAppleAccount.last_name`. .. py:method:: export() -> dict See `BaseAppleAccount.export`. .. py:method:: restore(data: dict) -> None See `BaseAppleAccount.restore`. .. py:method:: close() -> None :async: Close any sessions or other resources in use by this object. Should be called when the object will no longer be used. .. py:method:: login(username: str, password: str) -> findmy.reports.state.LoginState :async: See `BaseAppleAccount.login`. .. py:method:: get_2fa_methods() -> Sequence[findmy.reports.twofactor.AsyncSecondFactorMethod] :async: See `BaseAppleAccount.get_2fa_methods`. .. py:method:: sms_2fa_request(phone_number_id: int) -> None :async: See `BaseAppleAccount.sms_2fa_request`. .. py:method:: sms_2fa_submit(phone_number_id: int, code: str) -> findmy.reports.state.LoginState :async: See `BaseAppleAccount.sms_2fa_submit`. .. py:method:: td_2fa_request() -> None :async: See `BaseAppleAccount.td_2fa_request`. .. py:method:: td_2fa_submit(code: str) -> findmy.reports.state.LoginState :async: See `BaseAppleAccount.td_2fa_submit`. .. py:method:: fetch_raw_reports(start: int, end: int, ids: list[str]) -> dict[str, Any] :async: Make a request for location reports, returning raw data. .. py:method:: fetch_reports(keys: findmy.keys.HasHashedPublicKey, date_from: datetime.datetime, date_to: datetime.datetime | None) -> list[findmy.reports.reports.LocationReport] fetch_reports(keys: Sequence[findmy.keys.HasHashedPublicKey], date_from: datetime.datetime, date_to: datetime.datetime | None) -> dict[findmy.keys.HasHashedPublicKey, list[findmy.reports.reports.LocationReport]] fetch_reports(keys: findmy.accessory.RollingKeyPairSource, date_from: datetime.datetime, date_to: datetime.datetime | None) -> list[findmy.reports.reports.LocationReport] :async: See `BaseAppleAccount.fetch_reports`. .. py:method:: fetch_last_reports(keys: findmy.keys.HasHashedPublicKey, hours: int = 7 * 24) -> list[findmy.reports.reports.LocationReport] fetch_last_reports(keys: Sequence[findmy.keys.HasHashedPublicKey], hours: int = 7 * 24) -> dict[findmy.keys.HasHashedPublicKey, list[findmy.reports.reports.LocationReport]] fetch_last_reports(keys: findmy.accessory.RollingKeyPairSource, hours: int = 7 * 24) -> list[findmy.reports.reports.LocationReport] :async: See `BaseAppleAccount.fetch_last_reports`. .. py:method:: get_anisette_headers(with_client_info: bool = False, serial: str = '0') -> dict[str, str] :async: See `BaseAppleAccount.get_anisette_headers`. .. py:class:: BaseAnisetteProvider(loop: asyncio.AbstractEventLoop | None = None) Bases: :py:obj:`findmy.util.closable.Closable`, :py:obj:`abc.ABC` Abstract base class for Anisette providers. Generously derived from https://github.com/nythepegasus/grandslam/blob/main/src/grandslam/gsa.py#L41. .. py:property:: otp :type: str :abstractmethod: A seemingly random base64 string containing 28 bytes. TODO: Figure out how to generate this. .. py:property:: machine :type: str :abstractmethod: A base64 encoded string of 60 'random' bytes. We're not sure how this is generated, we have to rely on the server. TODO: Figure out how to generate this. .. py:property:: timestamp :type: str Current timestamp in ISO 8601 format. .. py:property:: timezone :type: str Abbreviation of the timezone of the device. .. py:property:: locale :type: str Locale of the device (e.g. en_US). .. py:property:: router :type: str A number, either 17106176 or 50660608. It doesn't seem to matter which one we use. - 17106176 is used by Sideloadly and Provision (android) based servers. - 50660608 is used by Windows iCloud based servers. .. py:property:: client :type: str Client string. The format is as follows: <%MODEL%> <%OS%;%MAJOR%.%MINOR%(%SPMAJOR%,%SPMINOR%);%BUILD%> <%AUTHKIT_BUNDLE_ID%/%AUTHKIT_VERSION% (%APP_BUNDLE_ID%/%APP_VERSION%)> Where: MODEL: The model of the device (e.g. MacBookPro15,1 or 'PC' OS: The OS of the device (e.g. Mac OS X or Windows) MAJOR: The major version of the OS (e.g. 10) MINOR: The minor version of the OS (e.g. 15) SPMAJOR: The major version of the service pack (e.g. 0) (Windows only) SPMINOR: The minor version of the service pack (e.g. 0) (Windows only) BUILD: The build number of the OS (e.g. 19C57) AUTHKIT_BUNDLE_ID: The bundle ID of the AuthKit framework (e.g. com.apple.AuthKit) AUTHKIT_VERSION: The version of the AuthKit framework (e.g. 1) APP_BUNDLE_ID: The bundle ID of the app (e.g. com.apple.dt.Xcode) APP_VERSION: The version of the app (e.g. 3594.4.19) .. py:method:: get_headers(user_id: str, device_id: str, serial: str = '0', with_client_info: bool = False) -> dict[str, str] :async: Generate a complete dictionary of Anisette headers. Consider using `BaseAppleAccount.get_anisette_headers` instead. .. py:method:: get_cpd(user_id: str, device_id: str, serial: str = '0') -> dict[str, str] :async: Generate a complete dictionary of CPD data. Intended for internal use. .. py:class:: RemoteAnisetteProvider(server_url: str) Bases: :py:obj:`BaseAnisetteProvider` Anisette provider. Fetches headers from a remote Anisette server. .. py:property:: otp :type: str See `BaseAnisetteProvider.otp`_. .. py:property:: machine :type: str See `BaseAnisetteProvider.machine`_. .. py:method:: get_headers(user_id: str, device_id: str, serial: str = '0', with_client_info: bool = False) -> dict[str, str] :async: See `BaseAnisetteProvider.get_headers`_. .. py:method:: close() -> None :async: See `AnisetteProvider.close`. .. py:class:: LoginState Bases: :py:obj:`enum.Enum` Enum of possible login states. Used for `AppleAccount`'s internal state machine. .. py:attribute:: LOGGED_OUT :value: 0 .. py:attribute:: REQUIRE_2FA :value: 1 .. py:attribute:: AUTHENTICATED :value: 2 .. py:attribute:: LOGGED_IN :value: 3 .. py:method:: __lt__(other: LoginState) -> bool Compare against another `LoginState`. A `LoginState` is said to be "less than" another `LoginState` iff it is in an "earlier" stage of the login process, going from LOGGED_OUT to LOGGED_IN. .. py:method:: __repr__() -> str Human-readable string representation of the state. .. py:class:: SmsSecondFactorMethod(account: _AccType) Bases: :py:obj:`BaseSecondFactorMethod`, :py:obj:`abc.ABC` Base class for SMS-based two-factor authentication. .. py:property:: phone_number_id :type: int :abstractmethod: The phone number's ID. You most likely don't need this. .. py:property:: phone_number :type: str :abstractmethod: The 2FA method's phone number. May be masked using unicode characters; should only be used for identification purposes. .. py:class:: TrustedDeviceSecondFactorMethod(account: _AccType) Bases: :py:obj:`BaseSecondFactorMethod`, :py:obj:`abc.ABC` Base class for trusted device-based two-factor authentication.