Remove insecure parent seed endpoint

This commit is contained in:
thePR0M3TH3AN
2025-08-02 22:01:38 -04:00
parent 087b3bd657
commit 7aeba78245
5 changed files with 40 additions and 65 deletions

View File

@@ -430,25 +430,6 @@ def get_notifications(authorization: str | None = Header(None)) -> List[dict]:
return notes
@app.get("/api/v1/parent-seed")
def get_parent_seed(
authorization: str | None = Header(None),
file: str | None = None,
password: str | None = Header(None, alias="X-SeedPass-Password"),
) -> dict:
"""Return the parent seed or save it as an encrypted backup."""
_check_token(authorization)
_require_password(password)
assert _pm is not None
if file:
path = Path(file)
_pm.encryption_manager.encrypt_and_save_file(
_pm.parent_seed.encode("utf-8"), path
)
return {"status": "saved", "path": str(path)}
return {"seed": _pm.parent_seed}
@app.get("/api/v1/nostr/pubkey")
def get_nostr_pubkey(authorization: str | None = Header(None)) -> Any:
_check_token(authorization)
@@ -581,18 +562,24 @@ async def import_vault(
@app.post("/api/v1/vault/backup-parent-seed")
def backup_parent_seed(
data: dict | None = None, authorization: str | None = Header(None)
data: dict,
authorization: str | None = Header(None),
password: str | None = Header(None, alias="X-SeedPass-Password"),
) -> dict[str, str]:
"""Backup and reveal the parent seed."""
"""Create an encrypted backup of the parent seed after confirmation."""
_check_token(authorization)
_require_password(password)
assert _pm is not None
path = None
if data is not None:
p = data.get("path")
if p:
path = Path(p)
_pm.handle_backup_reveal_parent_seed(path)
return {"status": "ok"}
if not data.get("confirm"):
raise HTTPException(status_code=400, detail="Confirmation required")
path_str = data.get("path")
if not path_str:
raise HTTPException(status_code=400, detail="Missing path")
path = Path(path_str)
_pm.encryption_manager.encrypt_and_save_file(_pm.parent_seed.encode("utf-8"), path)
return {"status": "saved", "path": str(path)}
@app.post("/api/v1/change-password")

View File

@@ -155,30 +155,10 @@ def test_totp_codes_endpoint(client):
}
def test_parent_seed_endpoint(client, tmp_path):
def test_parent_seed_endpoint_removed(client):
cl, token = client
api._pm.parent_seed = "seed"
called = {}
api._pm.encryption_manager = SimpleNamespace(
encrypt_and_save_file=lambda data, path: called.setdefault("path", path)
)
headers = {
"Authorization": f"Bearer {token}",
"X-SeedPass-Password": "pw",
}
res = cl.get("/api/v1/parent-seed", headers=headers)
assert res.status_code == 200
assert res.json() == {"seed": "seed"}
out = tmp_path / "bk.enc"
res = cl.get("/api/v1/parent-seed", params={"file": str(out)}, headers=headers)
assert res.status_code == 200
assert res.json() == {"status": "saved", "path": str(out)}
assert called["path"] == out
res = cl.get("/api/v1/parent-seed", headers={"Authorization": f"Bearer {token}"})
assert res.status_code == 401
assert res.status_code == 404
def test_fingerprint_endpoints(client):
@@ -350,22 +330,31 @@ def test_vault_export_endpoint(client, tmp_path):
def test_backup_parent_seed_endpoint(client, tmp_path):
cl, token = client
api._pm.parent_seed = "seed"
called = {}
def backup(path=None):
called["path"] = path
api._pm.handle_backup_reveal_parent_seed = backup
api._pm.encryption_manager = SimpleNamespace(
encrypt_and_save_file=lambda data, path: called.setdefault("path", path)
)
path = tmp_path / "seed.enc"
headers = {"Authorization": f"Bearer {token}"}
headers = {
"Authorization": f"Bearer {token}",
"X-SeedPass-Password": "pw",
}
res = cl.post(
"/api/v1/vault/backup-parent-seed",
json={"path": str(path), "confirm": True},
headers=headers,
)
assert res.status_code == 200
assert res.json() == {"status": "saved", "path": str(path)}
assert called["path"] == path
res = cl.post(
"/api/v1/vault/backup-parent-seed",
json={"path": str(path)},
headers=headers,
)
assert res.status_code == 200
assert res.json() == {"status": "ok"}
assert called["path"] == path
assert res.status_code == 400
def test_relay_management_endpoints(client, dummy_nostr_client, monkeypatch):