findmy

Contents

findmy#

A package providing everything you need to work with Apple’s FindMy network.

Submodules#

Attributes#

Exceptions#

InvalidCredentialsError

Raised when credentials are incorrect.

InvalidStateError

Raised when a method is used that is in conflict with the internal account state.

UnauthorizedError

Raised when an authorization error occurs.

UnhandledProtocolError

Raised when an unexpected error occurs while communicating with Apple servers.

Classes#

FindMyAccessory

A findable Find My-accessory using official key rollover.

FindMyAccessoryMapping

JSON mapping representing state of a FindMyAccessory instance.

RollingKeyPairSource

A class that generates rolling :meth:`KeyPair`s.

HasHashedPublicKey

ABC for anything that has a public, hashed FindMy-key.

HasPublicKey

ABC for anything that has a public FindMy-key.

KeyPair

A private-public keypair for a trackable FindMy accessory.

KeyPairMapping

JSON mapping representing a KeyPair.

KeyPairType

Enum of possible key types.

AccountStateMapping

JSON mapping representing state of an Apple account instance.

AppleAccount

A sync implementation of BaseappleAccount().

AsyncAppleAccount

An async implementation of BaseAppleAccount().

AsyncSmsSecondFactor

An async implementation of SmsSecondFactorMethod().

AsyncTrustedDeviceSecondFactor

An async implementation of TrustedDeviceSecondFactorMethod().

BaseAnisetteProvider

Abstract base class for Anisette providers.

BaseAppleAccount

Base class for an Apple account.

BaseSecondFactorMethod

Base class for a second-factor authentication method for an Apple account.

LocalAnisetteMapping

JSON mapping representing state of a local Anisette provider.

LocalAnisetteProvider

Local anisette provider using the anisette library.

LocationReport

Location report corresponding to a certain HasHashedPublicKey().

LocationReportDecryptedMapping

JSON mapping representing a decrypted location report.

LocationReportEncryptedMapping

JSON mapping representing an encrypted location report.

LoginState

Enum of possible login states. Used for AppleAccount()'s internal state machine.

RemoteAnisetteMapping

JSON mapping representing state of a remote Anisette provider.

RemoteAnisetteProvider

Anisette provider. Fetches headers from a remote Anisette server.

SmsSecondFactorMethod

Base class for SMS-based two-factor authentication.

SyncSmsSecondFactor

A sync implementation of SmsSecondFactorMethod().

SyncTrustedDeviceSecondFactor

A sync implementation of TrustedDeviceSecondFactorMethod().

TrustedDeviceSecondFactorMethod

Base class for trusted device-based two-factor authentication.

NearbyOfflineFindingDevice

Offline-Finding device in nearby state.

OfflineFindingDevice

Device discoverable through Apple's bluetooth-based Offline Finding protocol.

OfflineFindingScanner

BLE scanner that searches for :meth:`OfflineFindingDevice`s.

SeparatedOfflineFindingDevice

Offline-Finding device in separated state.

Package Contents#

class findmy.FindMyAccessory(*, master_key: bytes, skn: bytes, sks: bytes, paired_at: datetime.datetime, name: str | None = None, model: str | None = None, identifier: str | None = None, alignment_date: datetime.datetime | None = None, alignment_index: int | None = None)#

Bases: RollingKeyPairSource, findmy.util.abc.Serializable[FindMyAccessoryMapping]

Inheritance diagram of findmy.FindMyAccessory

A findable Find My-accessory using official key rollover.

property master_key: bytes#

The private master key.

property skn: bytes#

The SKN for the primary key.

property sks: bytes#

The SKS for the secondary key.

property paired_at: datetime.datetime#

Date and time at which this accessory was paired with an Apple account.

property name: str | None#

Name of this accessory.

property model: str | None#

Model string of this accessory, as provided by the manufacturer.

property identifier: str | None#

Internal identifier of this accessory.

property interval: datetime.timedelta#

Official FindMy accessory rollover interval (15 minutes).

get_min_index(dt: datetime.datetime) int#

Get the minimum key index that the accessory could be broadcasting at a specific time.

get_max_index(dt: datetime.datetime) int#

Get the maximum key index that the accessory could be broadcasting at a specific time.

update_alignment(dt: datetime.datetime, index: int) None#

Update alignment of the accessory based on a key index that was observed at a specific time.

Implementations of this method should consider that this method may be called multiple times, sometimes with seemingly conflicting data: the same index may be observed at different times, or multiple indices may be observed at the same time.

keys_at(ind: int) set[findmy.keys.KeyPair]#

Get the primary and secondary keys that might be active at a certain index.

classmethod from_plist(plist: str | pathlib.Path | dict | bytes, key_alignment_plist: str | pathlib.Path | dict | bytes | None = None, *, name: str | None = None) FindMyAccessory#

Create a FindMyAccessory from a .plist file dumped from the FindMy app.

to_json(path: str | pathlib.Path | None = None, /) FindMyAccessoryMapping#

Export the current state of the object as a JSON-serializable dictionary.

If an argument is provided, the output will also be written to that file.

The output of this method is guaranteed to be JSON-serializable, and passing the return value of this function as an argument to Serializable.from_json() will always result in an exact copy of the internal state as it was when exported.

You are encouraged to save and load object states to and from disk whenever possible, to prevent unnecessary API calls or otherwise unexpected behavior.

classmethod from_json(val: str | pathlib.Path | FindMyAccessoryMapping, /) FindMyAccessory#

Restore state from a previous Closable.to_json() export.

If given a str or Path, it must point to a json file from Serializable.to_json(). Otherwise, it should be the Mapping itself.

See Serializable.to_json() for more information.

class findmy.FindMyAccessoryMapping#

Bases: TypedDict

Inheritance diagram of findmy.FindMyAccessoryMapping

JSON mapping representing state of a FindMyAccessory instance.

type: Literal['accessory']#
master_key: str#
skn: str#
sks: str#
paired_at: str#
name: str | None#
model: str | None#
identifier: str | None#
alignment_date: str | None#
alignment_index: int | None#
class findmy.RollingKeyPairSource#

Bases: abc.ABC

Inheritance diagram of findmy.RollingKeyPairSource

A class that generates rolling :meth:`KeyPair`s.

property interval: datetime.timedelta#
Abstractmethod:

KeyPair rollover interval.

abstractmethod get_min_index(dt: datetime.datetime) int#

Get the minimum key index that the accessory could be broadcasting at a specific time.

abstractmethod get_max_index(dt: datetime.datetime) int#

Get the maximum key index that the accessory could be broadcasting at a specific time.

abstractmethod update_alignment(dt: datetime.datetime, index: int) None#

Update alignment of the accessory based on a key index that was observed at a specific time.

Implementations of this method should consider that this method may be called multiple times, sometimes with seemingly conflicting data: the same index may be observed at different times, or multiple indices may be observed at the same time.

abstractmethod keys_at(ind: int) set[findmy.keys.KeyPair]#

Generate potential key(s) occurring at a certain index.

keys_between(start: int | datetime.datetime, end: int | datetime.datetime) collections.abc.Generator[tuple[int, findmy.keys.KeyPair], None, None]#

Generate potential key(s) that could be occurring between two indices or datetimes.

exception findmy.InvalidCredentialsError#

Bases: Exception

Inheritance diagram of findmy.InvalidCredentialsError

Raised when credentials are incorrect.

exception findmy.InvalidStateError#

Bases: RuntimeError

Inheritance diagram of findmy.InvalidStateError

Raised when a method is used that is in conflict with the internal account state.

For example: calling BaseAppleAccount.login() while already logged in.

exception findmy.UnauthorizedError#

Bases: Exception

Inheritance diagram of findmy.UnauthorizedError

Raised when an authorization error occurs.

exception findmy.UnhandledProtocolError#

Bases: RuntimeError

Inheritance diagram of findmy.UnhandledProtocolError

Raised when an unexpected error occurs while communicating with Apple servers.

This is almost always a bug, so please report it.

class findmy.HasHashedPublicKey#

Bases: abc.ABC

Inheritance diagram of findmy.HasHashedPublicKey

ABC for anything that has a public, hashed FindMy-key.

Also called a “hashed advertisement” key or “lookup” key.

property hashed_adv_key_bytes: bytes#
Abstractmethod:

Return the hashed advertised (public) key as bytes.

property hashed_adv_key_b64: str#

Return the hashed advertised (public) key as a base64-encoded string.

__hash__() int#
__eq__(other: object) bool#
class findmy.HasPublicKey#

Bases: HasHashedPublicKey, abc.ABC

Inheritance diagram of findmy.HasPublicKey

ABC for anything that has a public FindMy-key.

Also called an “advertisement” key, since it is the key that is advertised by findable devices.

property adv_key_bytes: bytes#
Abstractmethod:

Return the advertised (public) key as bytes.

property adv_key_b64: str#

Return the advertised (public) key as a base64-encoded string.

property hashed_adv_key_bytes: bytes#

See HasHashedPublicKey.hashed_adv_key_bytes().

property mac_address: str#

Get the mac address from the public key.

adv_data(status: int = 0, hint: int = 0) bytes#

Get the BLE advertisement data that should be broadcast to advertise this key.

of_data(status: int = 0, hint: int = 0) bytes#

Get the Offline Finding data that should be broadcast to advertise this key.

class findmy.KeyPair(private_key: bytes, key_type: KeyPairType = KeyPairType.UNKNOWN, name: str | None = None)#

Bases: HasPublicKey, findmy.util.abc.Serializable[KeyPairMapping]

Inheritance diagram of findmy.KeyPair

A private-public keypair for a trackable FindMy accessory.

property key_type: KeyPairType#

Type of this key.

property name: str | None#

Name of this KeyPair.

classmethod new() KeyPair#

Generate a new random KeyPair().

classmethod from_b64(key_b64: str) KeyPair#

Import an existing KeyPair() from its base64-encoded representation.

Same format as returned by KeyPair.private_key_b64().

property private_key_bytes: bytes#

Return the private key as bytes.

property private_key_b64: str#

Return the private key as a base64-encoded string.

Can be re-imported using KeyPair.from_b64().

property adv_key_bytes: bytes#

Return the advertised (public) key as bytes.

to_json(dst: str | pathlib.Path | None = None, /) KeyPairMapping#

Export the current state of the object as a JSON-serializable dictionary.

If an argument is provided, the output will also be written to that file.

The output of this method is guaranteed to be JSON-serializable, and passing the return value of this function as an argument to Serializable.from_json() will always result in an exact copy of the internal state as it was when exported.

You are encouraged to save and load object states to and from disk whenever possible, to prevent unnecessary API calls or otherwise unexpected behavior.

classmethod from_json(val: str | pathlib.Path | KeyPairMapping, /) KeyPair#

Restore state from a previous Closable.to_json() export.

If given a str or Path, it must point to a json file from Serializable.to_json(). Otherwise, it should be the Mapping itself.

See Serializable.to_json() for more information.

dh_exchange(other_pub_key: cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey) bytes#

Do a Diffie-Hellman key exchange using another EC public key.

__repr__() str#
class findmy.KeyPairMapping#

Bases: TypedDict

Inheritance diagram of findmy.KeyPairMapping

JSON mapping representing a KeyPair.

type: Literal['keypair']#
private_key: str#
key_type: int#
name: str | None#
class findmy.KeyPairType(*args, **kwds)#

Bases: enum.Enum

Inheritance diagram of findmy.KeyPairType

Enum of possible key types.

UNKNOWN = 0#
PRIMARY = 1#
SECONDARY = 2#
class findmy.AccountStateMapping#

Bases: TypedDict

JSON mapping representing state of an Apple account instance.

type: Literal['account']#
ids: _AccountStateMappingIds#
account: _AccountStateMappingAccount#
login: _AccountStateMappingLoginState#
anisette: findmy.reports.anisette.AnisetteMapping#
findmy.AnisetteMapping#
class findmy.AppleAccount(anisette: findmy.reports.anisette.BaseAnisetteProvider, *, state_info: AccountStateMapping | None = None)#

Bases: BaseAppleAccount

A sync implementation of BaseappleAccount().

Uses AsyncappleAccount() internally.

async close() None#

See AsyncAppleAccount.close().

property login_state: findmy.reports.state.LoginState#

See AsyncAppleAccount.login_state().

property account_name: str | None#

See AsyncAppleAccount.login_state().

property first_name: str | None#

See AsyncAppleAccount.first_name().

property last_name: str | None#

See AsyncAppleAccount.last_name().

to_json(dst: str | pathlib.Path | None = None, /) AccountStateMapping#

Export the current state of the object as a JSON-serializable dictionary.

If an argument is provided, the output will also be written to that file.

The output of this method is guaranteed to be JSON-serializable, and passing the return value of this function as an argument to Serializable.from_json() will always result in an exact copy of the internal state as it was when exported.

You are encouraged to save and load object states to and from disk whenever possible, to prevent unnecessary API calls or otherwise unexpected behavior.

classmethod from_json(val: str | pathlib.Path | AccountStateMapping, /, *, anisette_libs_path: str | pathlib.Path | None = None) AppleAccount#

Restore state from a previous Closable.to_json() export.

If given a str or Path, it must point to a json file from Serializable.to_json(). Otherwise, it should be the Mapping itself.

See Serializable.to_json() for more information.

login(username: str, password: str) findmy.reports.state.LoginState#

See AsyncAppleAccount.login().

get_2fa_methods() collections.abc.Sequence[findmy.reports.twofactor.SyncSecondFactorMethod]#

See AsyncAppleAccount.get_2fa_methods().

sms_2fa_request(phone_number_id: int) None#

See AsyncAppleAccount.sms_2fa_request().

sms_2fa_submit(phone_number_id: int, code: str) findmy.reports.state.LoginState#

See AsyncAppleAccount.sms_2fa_submit().

td_2fa_request() None#

See AsyncAppleAccount.td_2fa_request().

td_2fa_submit(code: str) findmy.reports.state.LoginState#

See AsyncAppleAccount.td_2fa_submit().

fetch_location_history(keys: findmy.keys.HasHashedPublicKey) list[findmy.reports.reports.LocationReport]#
fetch_location_history(keys: findmy.accessory.RollingKeyPairSource) list[findmy.reports.reports.LocationReport]
fetch_location_history(keys: collections.abc.Sequence[findmy.keys.HasHashedPublicKey | findmy.accessory.RollingKeyPairSource]) dict[findmy.keys.HasHashedPublicKey | findmy.accessory.RollingKeyPairSource, list[findmy.reports.reports.LocationReport]]

See BaseAppleAccount.fetch_location_history.

fetch_location(keys: findmy.keys.HasHashedPublicKey) findmy.reports.reports.LocationReport | None#
fetch_location(keys: findmy.accessory.RollingKeyPairSource) findmy.reports.reports.LocationReport | None
fetch_location(keys: collections.abc.Sequence[findmy.keys.HasHashedPublicKey | findmy.accessory.RollingKeyPairSource]) dict[findmy.keys.HasHashedPublicKey | findmy.accessory.RollingKeyPairSource, findmy.reports.reports.LocationReport | None]

See BaseAppleAccount.fetch_location().

get_anisette_headers(with_client_info: bool = False, serial: str = '0') dict[str, str]#

See AsyncAppleAccount.get_anisette_headers().

class findmy.AsyncAppleAccount(anisette: findmy.reports.anisette.BaseAnisetteProvider, *, state_info: AccountStateMapping | None = None)#

Bases: BaseAppleAccount

An async implementation of BaseAppleAccount().

property login_state: findmy.reports.state.LoginState#

See BaseAppleAccount.login_state().

property account_name: str | None#

See BaseAppleAccount.account_name().

property first_name: str | None#

See BaseAppleAccount.first_name().

property last_name: str | None#

See BaseAppleAccount.last_name().

to_json(path: str | pathlib.Path | None = None, /) AccountStateMapping#

Export the current state of the object as a JSON-serializable dictionary.

If an argument is provided, the output will also be written to that file.

The output of this method is guaranteed to be JSON-serializable, and passing the return value of this function as an argument to Serializable.from_json() will always result in an exact copy of the internal state as it was when exported.

You are encouraged to save and load object states to and from disk whenever possible, to prevent unnecessary API calls or otherwise unexpected behavior.

classmethod from_json(val: str | pathlib.Path | AccountStateMapping, /, *, anisette_libs_path: str | pathlib.Path | None = None) AsyncAppleAccount#

Restore state from a previous Closable.to_json() export.

If given a str or Path, it must point to a json file from Serializable.to_json(). Otherwise, it should be the Mapping itself.

See Serializable.to_json() for more information.

async close() None#

Close any sessions or other resources in use by this object.

Should be called when the object will no longer be used.

async login(username: str, password: str) findmy.reports.state.LoginState#

See BaseAppleAccount.login().

async get_2fa_methods() collections.abc.Sequence[findmy.reports.twofactor.AsyncSecondFactorMethod]#

See BaseAppleAccount.get_2fa_methods().

async sms_2fa_request(phone_number_id: int) None#

See BaseAppleAccount.sms_2fa_request().

async sms_2fa_submit(phone_number_id: int, code: str) findmy.reports.state.LoginState#

See BaseAppleAccount.sms_2fa_submit().

async td_2fa_request() None#

See BaseAppleAccount.td_2fa_request().

async td_2fa_submit(code: str) findmy.reports.state.LoginState#

See BaseAppleAccount.td_2fa_submit().

async fetch_raw_reports(devices: list[tuple[list[str], list[str]]]) list[findmy.reports.reports.LocationReport]#

Make a request for location reports, returning raw data.

async fetch_location_history(keys: findmy.keys.HasHashedPublicKey) list[findmy.reports.reports.LocationReport]#
async fetch_location_history(keys: findmy.accessory.RollingKeyPairSource) list[findmy.reports.reports.LocationReport]
async fetch_location_history(keys: collections.abc.Sequence[findmy.keys.HasHashedPublicKey | findmy.accessory.RollingKeyPairSource]) dict[findmy.keys.HasHashedPublicKey | findmy.accessory.RollingKeyPairSource, list[findmy.reports.reports.LocationReport]]

See BaseAppleAccount.fetch_location_history.

async fetch_location(keys: findmy.keys.HasHashedPublicKey) findmy.reports.reports.LocationReport | None#
async fetch_location(keys: findmy.accessory.RollingKeyPairSource) findmy.reports.reports.LocationReport | None
async fetch_location(keys: collections.abc.Sequence[findmy.keys.HasHashedPublicKey | findmy.accessory.RollingKeyPairSource]) dict[findmy.keys.HasHashedPublicKey | findmy.accessory.RollingKeyPairSource, findmy.reports.reports.LocationReport | None]

See BaseAppleAccount.fetch_location().

async get_anisette_headers(with_client_info: bool = False, serial: str = '0') dict[str, str]#

See BaseAppleAccount.get_anisette_headers().

class findmy.AsyncSmsSecondFactor(account: findmy.reports.account.AsyncAppleAccount, number_id: int, phone_number: str)#

Bases: AsyncSecondFactorMethod, SmsSecondFactorMethod

An async implementation of SmsSecondFactorMethod().

property phone_number_id: int#

The phone number’s ID. You most likely don’t need this.

property phone_number: str#

The 2FA method’s phone number.

May be masked using unicode characters; should only be used for identification purposes.

async request() None#

Request an SMS to the corresponding phone number containing a 2FA code.

async submit(code: str) findmy.reports.state.LoginState#

Submit the 2FA code as received over SMS.

class findmy.AsyncTrustedDeviceSecondFactor(account: findmy.reports.account.AsyncAppleAccount)#

Bases: AsyncSecondFactorMethod, TrustedDeviceSecondFactorMethod

An async implementation of TrustedDeviceSecondFactorMethod().

async request() None#

See BaseSecondFactorMethod.request().

async submit(code: str) findmy.reports.state.LoginState#

See BaseSecondFactorMethod.submit().

class findmy.BaseAnisetteProvider(loop: asyncio.AbstractEventLoop | None = None)#

Bases: findmy.util.abc.Closable, findmy.util.abc.Serializable, abc.ABC

Abstract base class for Anisette providers.

Generously derived from nythepegasus/grandslam.

property otp: str#
Abstractmethod:

A seemingly random base64 string containing 28 bytes.

property machine: str#
Abstractmethod:

A base64 encoded string of 60 ‘random’ bytes.

property timestamp: str#

Current timestamp in ISO 8601 format.

property timezone: str#

Abbreviation of the timezone of the device.

property locale: str#

Locale of the device (e.g. en_US).

property router: 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.

property client: 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)

async get_headers(user_id: str, device_id: str, serial: str = '0', with_client_info: bool = False) dict[str, str]#

Generate a complete dictionary of Anisette headers.

Consider using BaseAppleAccount.get_anisette_headers() instead.

async get_cpd(user_id: str, device_id: str, serial: str = '0') dict[str, str]#

Generate a complete dictionary of CPD data.

Intended for internal use.

class findmy.BaseAppleAccount(loop: asyncio.AbstractEventLoop | None = None)#

Bases: findmy.util.abc.Closable, findmy.util.abc.Serializable[AccountStateMapping], abc.ABC

Base class for an Apple account.

property login_state: findmy.reports.state.LoginState#
Abstractmethod:

The current login state of the account.

property account_name: str | None#
Abstractmethod:

The name of the account as reported by Apple.

This is usually an e-mail address. May be None in some cases, such as when not logged in.

property first_name: str | None#
Abstractmethod:

First name of the account holder as reported by Apple.

May be None in some cases, such as when not logged in.

property last_name: str | None#
Abstractmethod:

Last name of the account holder as reported by Apple.

May be None in some cases, such as when not logged in.

abstractmethod login(username: str, password: str) findmy.util.types.MaybeCoro[findmy.reports.state.LoginState]#

Log in to an Apple account using a username and password.

abstractmethod get_2fa_methods() findmy.util.types.MaybeCoro[collections.abc.Sequence[findmy.reports.twofactor.BaseSecondFactorMethod]]#

Get a list of 2FA methods that can be used as a secondary challenge.

Currently, only SMS-based 2FA methods are supported.

abstractmethod sms_2fa_request(phone_number_id: int) findmy.util.types.MaybeCoro[None]#

Request a 2FA code to be sent to a specific phone number ID.

Consider using BaseSecondFactorMethod.request() instead.

abstractmethod sms_2fa_submit(phone_number_id: int, code: str) findmy.util.types.MaybeCoro[findmy.reports.state.LoginState]#

Submit a 2FA code that was sent to a specific phone number ID.

Consider using BaseSecondFactorMethod.submit() instead.

abstractmethod td_2fa_request() findmy.util.types.MaybeCoro[None]#

Request a 2FA code to be sent to a trusted device.

Consider using BaseSecondFactorMethod.request() instead.

abstractmethod td_2fa_submit(code: str) findmy.util.types.MaybeCoro[findmy.reports.state.LoginState]#

Submit a 2FA code that was sent to a trusted device.

Consider using BaseSecondFactorMethod.submit() instead.

abstractmethod fetch_location_history(keys: findmy.keys.HasHashedPublicKey) findmy.util.types.MaybeCoro[list[findmy.reports.reports.LocationReport]]#
abstractmethod fetch_location_history(keys: findmy.accessory.RollingKeyPairSource) findmy.util.types.MaybeCoro[list[findmy.reports.reports.LocationReport]]
abstractmethod fetch_location_history(keys: collections.abc.Sequence[findmy.keys.HasHashedPublicKey | findmy.accessory.RollingKeyPairSource]) findmy.util.types.MaybeCoro[dict[findmy.keys.HasHashedPublicKey | findmy.accessory.RollingKeyPairSource, list[findmy.reports.reports.LocationReport]]]

Fetch location history for :class:`HasHashedPublicKey`s and :class:`RollingKeyPairSource`s.

Note that location history for devices is provided on a best-effort basis and may not be fully complete or stable. Multiple consecutive calls to this method may result in different location reports, especially for reports further in the past. However, each one of these reports is guaranteed to be in line with the data reported by Apple, and the most recent report will always be included in the results.

Unless you really need to use this method, and use fetch_location() instead.

abstractmethod fetch_location(keys: findmy.keys.HasHashedPublicKey) findmy.util.types.MaybeCoro[findmy.reports.reports.LocationReport | None]#
abstractmethod fetch_location(keys: findmy.accessory.RollingKeyPairSource) findmy.util.types.MaybeCoro[findmy.reports.reports.LocationReport | None]
abstractmethod fetch_location(keys: collections.abc.Sequence[findmy.keys.HasHashedPublicKey | findmy.accessory.RollingKeyPairSource]) findmy.util.types.MaybeCoro[dict[findmy.keys.HasHashedPublicKey | findmy.accessory.RollingKeyPairSource, findmy.reports.reports.LocationReport | None] | None]

Fetch location for :class:`HasHashedPublicKey`s.

Returns a dictionary mapping :class:`HasHashedPublicKey`s to their location reports.

abstractmethod get_anisette_headers(with_client_info: bool = False, serial: str = '0') findmy.util.types.MaybeCoro[dict[str, str]]#

Retrieve a complete dictionary of Anisette headers.

Utility method for AnisetteProvider.get_headers() using this account’s user/device ID.

class findmy.BaseSecondFactorMethod(account: _AccType)#

Bases: abc.ABC, Generic[_AccType]

Base class for a second-factor authentication method for an Apple account.

property account: _AccType#

The account associated with the second-factor method.

abstractmethod request() findmy.util.types.MaybeCoro[None]#

Put in a request for the second-factor challenge.

Exact meaning is up to the implementing class.

abstractmethod submit(code: str) findmy.util.types.MaybeCoro[findmy.reports.state.LoginState]#

Submit a code to complete the second-factor challenge.

class findmy.LocalAnisetteMapping#

Bases: TypedDict

JSON mapping representing state of a local Anisette provider.

type: Literal['aniLocal']#
prov_data: str#
class findmy.LocalAnisetteProvider(*, state_blob: BinaryIO | None = None, libs_path: str | pathlib.Path | None = None)#

Bases: BaseAnisetteProvider, findmy.util.abc.Serializable[LocalAnisetteMapping]

Local anisette provider using the anisette library.

to_json(dst: str | pathlib.Path | None = None, /) LocalAnisetteMapping#

See BaseAnisetteProvider.serialize().

classmethod from_json(val: str | pathlib.Path | LocalAnisetteMapping, *, libs_path: str | pathlib.Path | None = None) LocalAnisetteProvider#

See BaseAnisetteProvider.deserialize().

async get_headers(user_id: str, device_id: str, serial: str = '0', with_client_info: bool = False) dict[str, str]#

See BaseAnisetteProvider.get_headers().

property otp: str#

See BaseAnisetteProvider.otp().

property machine: str#

See BaseAnisetteProvider.machine().

async close() None#

See BaseAnisetteProvider.close().

class findmy.LocationReport(payload: bytes, hashed_adv_key: bytes)#

Bases: findmy.keys.HasHashedPublicKey, findmy.util.abc.Serializable[LocationReportMapping]

Location report corresponding to a certain HasHashedPublicKey().

property hashed_adv_key_bytes: bytes#

See HasHashedPublicKey.hashed_adv_key_bytes().

property key: findmy.keys.KeyPair#

KeyPair using which this report was decrypted.

property payload: bytes#

Full (partially encrypted) payload of the report, as retrieved from Apple.

property is_decrypted: bool#

Whether the report is currently decrypted.

can_decrypt(key: findmy.keys.KeyPair, /) bool#

Whether the report can be decrypted using the given key.

decrypt(key: findmy.keys.KeyPair) None#

Decrypt the report using its corresponding KeyPair().

property timestamp: datetime.datetime#

The datetime() when this report was recorded by a device.

property confidence: int#

Confidence of the location of this report. Int between 1 and 3.

property latitude: float#

Latitude of the location of this report.

property longitude: float#

Longitude of the location of this report.

property horizontal_accuracy: int#

Horizontal accuracy of the location of this report.

property status: int#

Status byte of the accessory as recorded by a device, as an integer.

to_json(dst: str | pathlib.Path | None = None, /, *, include_key: Literal[True]) LocationReportEncryptedMapping#
to_json(dst: str | pathlib.Path | None = None, /, *, include_key: Literal[False]) LocationReportDecryptedMapping
to_json(dst: str | pathlib.Path | None = None, /, *, include_key: None = None) LocationReportMapping

Export the current state of the object as a JSON-serializable dictionary.

If an argument is provided, the output will also be written to that file.

The output of this method is guaranteed to be JSON-serializable, and passing the return value of this function as an argument to Serializable.from_json() will always result in an exact copy of the internal state as it was when exported.

You are encouraged to save and load object states to and from disk whenever possible, to prevent unnecessary API calls or otherwise unexpected behavior.

classmethod from_json(val: str | pathlib.Path | LocationReportMapping, /) LocationReport#

Restore state from a previous Closable.to_json() export.

If given a str or Path, it must point to a json file from Serializable.to_json(). Otherwise, it should be the Mapping itself.

See Serializable.to_json() for more information.

__eq__(other: object) bool#

Compare two report instances.

Two reports are considered equal iff they correspond to the same key, were reported at the same timestamp and represent the same physical location.

__hash__() int#

Get the hash of this instance.

Two instances will have the same hash iff they correspond to the same key, were reported at the same timestamp and represent the same physical location.

__lt__(other: LocationReport) bool#

Compare against another LocationReport().

A LocationReport() is said to be “less than” another LocationReport() iff its recorded timestamp is strictly less than the other report.

__repr__() str#

Human-readable string representation of the location report.

class findmy.LocationReportDecryptedMapping#

Bases: TypedDict

JSON mapping representing a decrypted location report.

type: Literal['locReportDecrypted']#
payload: str#
hashed_adv_key: str#
key: findmy.keys.KeyPairMapping#
class findmy.LocationReportEncryptedMapping#

Bases: TypedDict

JSON mapping representing an encrypted location report.

type: Literal['locReportEncrypted']#
payload: str#
hashed_adv_key: str#
findmy.LocationReportMapping#
class findmy.LoginState(*args, **kwds)#

Bases: enum.Enum

Enum of possible login states. Used for AppleAccount()’s internal state machine.

LOGGED_OUT = 0#
REQUIRE_2FA = 1#
AUTHENTICATED = 2#
LOGGED_IN = 3#
__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.

__repr__() str#

Human-readable string representation of the state.

class findmy.RemoteAnisetteMapping#

Bases: TypedDict

JSON mapping representing state of a remote Anisette provider.

type: Literal['aniRemote']#
url: str#
class findmy.RemoteAnisetteProvider(server_url: str)#

Bases: BaseAnisetteProvider, findmy.util.abc.Serializable[RemoteAnisetteMapping]

Anisette provider. Fetches headers from a remote Anisette server.

to_json(dst: str | pathlib.Path | None = None, /) RemoteAnisetteMapping#

See BaseAnisetteProvider.serialize().

classmethod from_json(val: str | pathlib.Path | RemoteAnisetteMapping) RemoteAnisetteProvider#

See BaseAnisetteProvider.deserialize().

property otp: str#

See BaseAnisetteProvider.otp().

property machine: str#

See BaseAnisetteProvider.machine().

async get_headers(user_id: str, device_id: str, serial: str = '0', with_client_info: bool = False) dict[str, str]#

See :meth:BaseAnisetteProvider.get_headers().

async close() None#

See AnisetteProvider.close().

class findmy.SmsSecondFactorMethod(account: _AccType)#

Bases: BaseSecondFactorMethod, abc.ABC

Base class for SMS-based two-factor authentication.

property phone_number_id: int#
Abstractmethod:

The phone number’s ID. You most likely don’t need this.

property phone_number: str#
Abstractmethod:

The 2FA method’s phone number.

May be masked using unicode characters; should only be used for identification purposes.

class findmy.SyncSmsSecondFactor(account: findmy.reports.account.AppleAccount, number_id: int, phone_number: str)#

Bases: SyncSecondFactorMethod, SmsSecondFactorMethod

A sync implementation of SmsSecondFactorMethod().

property phone_number_id: int#

See AsyncSmsSecondFactor.phone_number_id().

property phone_number: str#

See AsyncSmsSecondFactor.phone_number().

request() None#

See AsyncSmsSecondFactor.request().

submit(code: str) findmy.reports.state.LoginState#

See AsyncSmsSecondFactor.submit().

class findmy.SyncTrustedDeviceSecondFactor(account: findmy.reports.account.AppleAccount)#

Bases: SyncSecondFactorMethod, TrustedDeviceSecondFactorMethod

A sync implementation of TrustedDeviceSecondFactorMethod().

request() None#

See AsyncTrustedDeviceSecondFactor.request().

submit(code: str) findmy.reports.state.LoginState#

See AsyncTrustedDeviceSecondFactor.submit().

class findmy.TrustedDeviceSecondFactorMethod(account: _AccType)#

Bases: BaseSecondFactorMethod, abc.ABC

Base class for trusted device-based two-factor authentication.

class findmy.NearbyOfflineFindingDevice(mac_bytes: bytes, status_byte: int, first_adv_key_bytes: bytes, detected_at: datetime.datetime, additional_data: dict[Any, Any] | None = None)#

Bases: OfflineFindingDevice

Offline-Finding device in nearby state.

OF_PAYLOAD_LEN = 2#
is_from(other_device: findmy.keys.HasPublicKey | findmy.accessory.RollingKeyPairSource) bool#

Check whether the OF device’s identity originates from a specific key source.

classmethod from_payload(mac_address: str, payload: bytes, detected_at: datetime.datetime, additional_data: dict[Any, Any] | None = None) NearbyOfflineFindingDevice | None#

Get a NearbyOfflineFindingDevice object from an OF message payload.

class findmy.OfflineFindingDevice(mac_bytes: bytes, status_byte: int, detected_at: datetime.datetime, additional_data: dict[Any, Any] | None = None)#

Bases: abc.ABC

Device discoverable through Apple’s bluetooth-based Offline Finding protocol.

OF_HEADER_SIZE = 2#
OF_TYPE = 18#
property mac_address: str#

MAC address of the device in AA:BB:CC:DD:EE:FF format.

property status: int#

Status value as reported by the device.

property detected_at: datetime.datetime#

Timezone-aware datetime of when the device was detected.

property additional_data: dict[Any, Any]#

Any additional data. No guarantees about the contents of this dictionary.

abstractmethod is_from(other_device: findmy.keys.HasPublicKey | findmy.accessory.RollingKeyPairSource) bool#

Check whether the OF device’s identity originates from a specific key source.

classmethod from_payload(mac_address: str, payload: bytes, detected_at: datetime.datetime, additional_data: dict[Any, Any] | None) OfflineFindingDevice | None#
Abstractmethod:

Get a NearbyOfflineFindingDevice object from an OF message payload.

classmethod from_ble_payload(mac_address: str, ble_payload: bytes, detected_at: datetime.datetime | None = None, additional_data: dict[Any, Any] | None = None) OfflineFindingDevice | None#

Get a NearbyOfflineFindingDevice object from a BLE packet payload.

__eq__(other: object) bool#
__hash__() int#
class findmy.OfflineFindingScanner(loop: asyncio.AbstractEventLoop)#

BLE scanner that searches for :meth:`OfflineFindingDevice`s.

BLE_COMPANY_APPLE = 76#
classmethod create() OfflineFindingScanner#
Async:

Create an instance of the scanner.

async scan_for(timeout: float = 10, *, extend_timeout: bool = False) collections.abc.AsyncGenerator[OfflineFindingDevice, None]#

Scan for OfflineFindingDevice`s for up to :meth:`timeout() seconds.

If extend_timeout() is set, the timer will be extended by timeout() seconds every time a new device is discovered.

class findmy.SeparatedOfflineFindingDevice(mac_bytes: bytes, status: int, public_key: bytes, hint: int, detected_at: datetime.datetime, additional_data: dict[Any, Any] | None = None)#

Bases: OfflineFindingDevice, findmy.keys.HasPublicKey

Offline-Finding device in separated state.

OF_PAYLOAD_LEN = 25#
property hint: int#

Hint value as reported by the device.

property adv_key_bytes: bytes#

See HasPublicKey.adv_key_bytes().

is_from(other_device: findmy.keys.HasPublicKey | findmy.accessory.RollingKeyPairSource) bool#

Check whether the OF device’s identity originates from a specific key source.

classmethod from_payload(mac_address: str, payload: bytes, detected_at: datetime.datetime, additional_data: dict[Any, Any] | None = None) SeparatedOfflineFindingDevice | None#

Get a SeparatedOfflineFindingDevice object from an OF message payload.

__repr__() str#

Human-readable string representation of an OfflineFindingDevice.