Skip to content

Conversation

Copy link

Copilot AI commented Nov 1, 2025

Implements v2 package structure with FmdClient (low-level API) and Device (high-level wrapper) classes, porting all core behaviors from the existing fmd_api.py module while preserving authentication flow, encryption/decryption semantics, and API compatibility.

Package Structure

  • fmd_api/init.py - Exports FmdClient, Device, typed exceptions
  • fmd_api/client.py - Full API implementation:
    • Authentication: salt → argon2id → requestAccess → RSA private key unwrap
    • Encryption: RSA-OAEP + AES-GCM data blob decryption
    • Commands: RSA-PSS signing with timestamp
    • Auto-reauth on 401, JSON/text fallback for server quirks
    • Convenience wrappers: request_location, take_picture, toggle_bluetooth, etc.
  • fmd_api/device.py - High-level wrapper:
    • refresh/get_location with caching
    • get_history with automatic decryption
    • play_sound, take_photo, fetch_pictures, download_photo
    • lock, wipe
  • fmd_api/types.py - Location and PhotoResult dataclasses
  • fmd_api/exceptions.py - FmdAuthenticationError, FmdDecryptionError, FmdApiRequestError, FmdInvalidDataError

Constants Preserved

All existing constants maintained (ARGON2 params, context strings, RSA key size 384 bytes, IV sizes 12 bytes).

Migration & Examples

  • docs/MIGRATE_FROM_V1.md - API mapping: FmdApi.get_all_locations()FmdClient.get_locations() / Device.get_history()
  • examples/async_example.py - Minimal usage example

Tests

22 pytest-asyncio tests (aioresponses for HTTP mocking):

  • tests/test_client.py - Authentication, locations, commands, reauth, export
  • tests/test_device.py - Location history, photo download, command wrappers

Usage

from fmd_api import Device

# High-level API (recommended)
device = await Device.create('https://fmd.example.com', 'device-id', 'password')
location = await device.get_location()
print(f"{location.latitude}, {location.longitude} - {location.battery}%")
await device.play_sound()

# Low-level API (for custom integrations)
from fmd_api import FmdClient
client = await FmdClient.create('https://fmd.example.com', 'device-id', 'password')
blobs = await client.get_locations(10)
decrypted = client.decrypt_data_blob(blobs[0])

Changes to pyproject.toml

  • Version bumped to 2.0.0
  • Removed unused requests dependency
  • Added aioresponses to dev dependencies
  • Updated package structure from single module to package discovery
Original prompt

Create a new feature branch named feature/v2-device-client and add a new package implementing fmd_api v2 (FmdClient + Device) with full port of core behaviors and tests. The branch should include the following files and contents (exact paths and summarized behavior):

  1. fmd_api/init.py - exports FmdClient, Device, exceptions
  2. fmd_api/_version.py - version string
  3. fmd_api/exceptions.py - typed exceptions
  4. fmd_api/types.py - dataclasses Location and PhotoResult
  5. fmd_api/helpers.py - base64 helpers
  6. fmd_api/client.py - full implementation ported from the repository's fmd_api.py: authenticate (salt -> argon2 -> requestAccess -> private key unwrap), decrypt_data_blob (RSA + AES-GCM), _make_api_request (aiohttp wrapper with reauth on 401 and JSON/text fallback), get_locations (port of get_all_locations), get_pictures, export_data_zip, send_command (RSA-PSS signing), and convenience wrappers (request_location, take_picture, toggle_bluetooth, toggle_do_not_disturb, set_ringer_mode, get_device_stats). Implementation must preserve current logic and constants (ARGON2 params, context strings, RSA key size, IV sizes).
  7. fmd_api/device.py - Device class that uses FmdClient to refresh/get_location, get_history (iterates decrypted blobs), play_sound, take front/rear photos, fetch_pictures, download_photo (decrypts picture blob), lock, wipe.
  8. docs/MIGRATE_FROM_V1.md - migration instructions mapping old functions to new client/device methods.
  9. examples/async_example.py - minimal usage example
  10. tests/test_client.py - pytest-asyncio tests covering get_locations+decrypt, send_command reauth, export_data_zip stream
  11. tests/test_device.py - tests for device refresh/get_location and fetch/download picture
  12. pyproject.toml, .gitignore

Commit description: "feat(v2): add FmdClient/Device package, port core fmd_api behaviors, and add tests"

Notes:

  • The implementation should be based on the existing fmd_api.py and README in the repo; preserve semantics and behavior for endpoints, decryption, and command signing.
  • Tests should use aioresponses to mock HTTP endpoints and cryptography primitives may be stubbed in tests as in the draft.
  • Do not add a legacy compatibility shim. Include the migration doc instead.

Please open a pull request from feature/v2-device-client into main with a concise PR title and description explaining the changes and listing included files. Link to this conversation context as necessary.

This pull request was created as a result of the following prompt from Copilot chat.

Create a new feature branch named feature/v2-device-client and add a new package implementing fmd_api v2 (FmdClient + Device) with full port of core behaviors and tests. The branch should include the following files and contents (exact paths and summarized behavior):

  1. fmd_api/init.py - exports FmdClient, Device, exceptions
  2. fmd_api/_version.py - version string
  3. fmd_api/exceptions.py - typed exceptions
  4. fmd_api/types.py - dataclasses Location and PhotoResult
  5. fmd_api/helpers.py - base64 helpers
  6. fmd_api/client.py - full implementation ported from the repository's fmd_api.py: authenticate (salt -> argon2 -> requestAccess -> private key unwrap), decrypt_data_blob (RSA + AES-GCM), _make_api_request (aiohttp wrapper with reauth on 401 and JSON/text fallback), get_locations (port of get_all_locations), get_pictures, export_data_zip, send_command (RSA-PSS signing), and convenience wrappers (request_location, take_picture, toggle_bluetooth, toggle_do_not_disturb, set_ringer_mode, get_device_stats). Implementation must preserve current logic and constants (ARGON2 params, context strings, RSA key size, IV sizes).
  7. fmd_api/device.py - Device class that uses FmdClient to refresh/get_location, get_history (iterates decrypted blobs), play_sound, take front/rear photos, fetch_pictures, download_photo (decrypts picture blob), lock, wipe.
  8. docs/MIGRATE_FROM_V1.md - migration instructions mapping old functions to new client/device methods.
  9. examples/async_example.py - minimal usage example
  10. tests/test_client.py - pytest-asyncio tests covering get_locations+decrypt, send_command reauth, export_data_zip stream
  11. tests/test_device.py - tests for device refresh/get_location and fetch/download picture
  12. pyproject.toml, .gitignore

Commit description: "feat(v2): add FmdClient/Device package, port core fmd_api behaviors, and add tests"

Notes:

  • The implementation should be based on the existing fmd_api.py and README in the repo; preserve semantics and behavior for endpoints, decryption, and command signing.
  • Tests should use aioresponses to mock HTTP endpoints and cryptography primitives may be stubbed in tests as in the draft.
  • Do not add a legacy compatibility shim. Include the migration doc instead.

Please open a pull request from feature/v2-device-client into main with a concise PR title and description explaining the changes and listing included files. Link to this conversation context as necessary.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

…and add tests

Co-authored-by: devinslick <1762071+devinslick@users.noreply.github.com>
Copilot AI changed the title [WIP] Add fmd_api v2 implementation with core behaviors and tests feat(v2): Add FmdClient/Device package with full API port and tests Nov 1, 2025
Copilot AI requested a review from devinslick November 1, 2025 18:28
@devinslick devinslick closed this Nov 3, 2025
@devinslick devinslick deleted the copilot/featurev2-device-client branch November 3, 2025 14:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants