Metadata-Version: 2.4
Name: tile-identity-resolver
Version: 0.1.0
Summary: Resolve Tile identities from FEED service data without Bluetooth dependencies
License-Expression: MIT
Project-URL: Homepage, https://github.com/kbck/tile-identity-resolver
Project-URL: Repository, https://github.com/kbck/tile-identity-resolver
Project-URL: Issues, https://github.com/kbck/tile-identity-resolver/issues
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Operating System :: OS Independent
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: test
Requires-Dist: pytest<9,>=8; extra == "test"
Provides-Extra: dev
Requires-Dist: pytest<9,>=8; extra == "dev"
Requires-Dist: ruff<1,>=0.11; extra == "dev"
Requires-Dist: build<2,>=1; extra == "dev"
Requires-Dist: mypy<3,>=1.15; extra == "dev"
Requires-Dist: twine<7,>=6; extra == "dev"
Requires-Dist: check-wheel-contents<1,>=0.6; extra == "dev"
Dynamic: license-file

# Tile Identity Resolver

A dependency-free Python library for identifying registered Tile trackers from
version-2 FEED service data. Requires Python 3.10 or newer.

## Install

```sh
python -m pip install tile-identity-resolver
```

## Usage

```python
from tile_identity_resolver import Tile, TileResolver

# Replace these example credentials with your Tile's ID and auth key.
tile = Tile(
    tile_id="0011223344556677",
    auth_key="AAECAwQFBgcICQoLDA0ODw==",
)
resolver = TileResolver([tile])

# Pass the raw service-data value for UUID 0000feed-0000-1000-8000-00805f9b34fb.
def handle_feed_payload(payload: bytes) -> None:
    info = resolver.resolve(payload)
    if info is not None:
        print(info.tile.tile_id, info.counter, info.version, info.flags)
```

Tile IDs are eight-byte lowercase hex strings. Auth keys are sixteen-byte hex
or padded Base64 strings. Invalid credentials raise `ValueError`.

## API

| API | Behavior |
| --- | --- |
| `TileResolver(tiles=())` | Register one or more Tiles |
| `resolver.add(tile)` | Register a Tile; duplicate IDs raise `ValueError` |
| `resolver.remove(tile_id)` | Remove a Tile; missing IDs raise `KeyError` |
| `resolver.tiles` | Immutable snapshot of registered Tiles |
| `resolver.resolve(payload)` | Return `TileInfo` for an unambiguous match, otherwise `None` |

`TileInfo` contains the registered `tile`, `counter`, `version`, and `flags`.
Remove and re-add a Tile to replace its key.

Registration precomputes private IDs and uses memory per Tile. In async apps,
prepare the resolver in a worker thread and serialize access during mutations.
The library resolves identities only; it does not track Bluetooth addresses or
presence, and a match does not prove freshness or proximity.

## Development

```sh
python -m pip install -e '.[dev]'
python tools/check_package.py
```

Runs tests, code checks, and package validation.

## Acknowledgements

Based on [Security and Privacy Analysis of Tile's Location Tracking Protocol](https://www.usenix.org/conference/usenixsecurity26/presentation/kumar-akshaya)
by Akshaya Kumar, Anna Raymaker, and Michael A. Specter (USENIX Security 2026).

Unofficial; not affiliated with Tile or Life360.
Licensed under the [MIT License](LICENSE).
