diff --git a/docs/docs/content/01-getting-started/02-api_reference.md b/docs/docs/content/01-getting-started/02-api_reference.md index 38af03a..25d52da 100644 --- a/docs/docs/content/01-getting-started/02-api_reference.md +++ b/docs/docs/content/01-getting-started/02-api_reference.md @@ -19,7 +19,7 @@ Keep this token secret and avoid logging it. Tokens expire after a few minutes a ## Endpoints - `GET /api/v1/entry?query=` – Search entries matching a query. -- `GET /api/v1/entry/{id}` – Retrieve a single entry by its index. +- `GET /api/v1/entry/{id}` – Retrieve a single entry by its index. Requires an `X-SeedPass-Password` header. - `POST /api/v1/entry` – Create a new entry of any supported type. - `PUT /api/v1/entry/{id}` – Modify an existing entry. - `PUT /api/v1/config/{key}` – Update a configuration value. @@ -31,8 +31,8 @@ Keep this token secret and avoid logging it. Tokens expire after a few minutes a - `POST /api/v1/fingerprint` – Add a new seed fingerprint. - `DELETE /api/v1/fingerprint/{fp}` – Remove a fingerprint. - `POST /api/v1/fingerprint/select` – Switch the active fingerprint. -- `GET /api/v1/totp/export` – Export all TOTP entries as JSON. -- `GET /api/v1/totp` – Return current TOTP codes and remaining time. +- `GET /api/v1/totp/export` – Export all TOTP entries as JSON. Requires an `X-SeedPass-Password` header. +- `GET /api/v1/totp` – Return current TOTP codes and remaining time. Requires an `X-SeedPass-Password` header. - `GET /api/v1/stats` – Return statistics about the active seed profile. - `GET /api/v1/notifications` – Retrieve and clear queued notifications. Messages appear in the persistent notification box but remain queued until fetched. - `GET /api/v1/nostr/pubkey` – Fetch the Nostr public key for the active seed. diff --git a/src/seedpass/api.py b/src/seedpass/api.py index f4b9864..61bc810 100644 --- a/src/seedpass/api.py +++ b/src/seedpass/api.py @@ -139,8 +139,13 @@ def search_entry(query: str, authorization: str | None = Header(None)) -> List[A @app.get("/api/v1/entry/{entry_id}") -def get_entry(entry_id: int, authorization: str | None = Header(None)) -> Any: +def get_entry( + entry_id: int, + authorization: str | None = Header(None), + password: str | None = Header(None, alias="X-SeedPass-Password"), +) -> Any: _check_token(authorization) + _require_password(password) assert _pm is not None entry = _pm.entry_manager.retrieve_entry(entry_id) if entry is None: @@ -417,17 +422,25 @@ def select_fingerprint( @app.get("/api/v1/totp/export") -def export_totp(authorization: str | None = Header(None)) -> dict: +def export_totp( + authorization: str | None = Header(None), + password: str | None = Header(None, alias="X-SeedPass-Password"), +) -> dict: """Return all stored TOTP entries in JSON format.""" _check_token(authorization) + _require_password(password) assert _pm is not None return _pm.entry_manager.export_totp_entries(_pm.parent_seed) @app.get("/api/v1/totp") -def get_totp_codes(authorization: str | None = Header(None)) -> dict: +def get_totp_codes( + authorization: str | None = Header(None), + password: str | None = Header(None, alias="X-SeedPass-Password"), +) -> dict: """Return active TOTP codes with remaining seconds.""" _check_token(authorization) + _require_password(password) assert _pm is not None entries = _pm.entry_manager.list_entries( filter_kind=EntryType.TOTP.value, include_archived=False diff --git a/src/tests/test_api.py b/src/tests/test_api.py index a44064c..67d0551 100644 --- a/src/tests/test_api.py +++ b/src/tests/test_api.py @@ -78,6 +78,7 @@ def test_get_entry_by_id(client): headers = { "Authorization": f"Bearer {token}", "Origin": "http://example.com", + "X-SeedPass-Password": "pw", } res = cl.get("/api/v1/entry/1", headers=headers) assert res.status_code == 200 diff --git a/src/tests/test_api_new_endpoints.py b/src/tests/test_api_new_endpoints.py index 8bb6232..d22cfbf 100644 --- a/src/tests/test_api_new_endpoints.py +++ b/src/tests/test_api_new_endpoints.py @@ -136,7 +136,7 @@ def test_totp_export_endpoint(client): cl, token = client api._pm.entry_manager.export_totp_entries = lambda seed: {"entries": ["x"]} api._pm.parent_seed = "seed" - headers = {"Authorization": f"Bearer {token}"} + headers = {"Authorization": f"Bearer {token}", "X-SeedPass-Password": "pw"} res = cl.get("/api/v1/totp/export", headers=headers) assert res.status_code == 200 assert res.json() == {"entries": ["x"]} @@ -148,7 +148,7 @@ def test_totp_codes_endpoint(client): api._pm.entry_manager.get_totp_code = lambda i, s: "123456" api._pm.entry_manager.get_totp_time_remaining = lambda i: 30 api._pm.parent_seed = "seed" - headers = {"Authorization": f"Bearer {token}"} + headers = {"Authorization": f"Bearer {token}", "X-SeedPass-Password": "pw"} res = cl.get("/api/v1/totp", headers=headers) assert res.status_code == 200 assert res.json() == {