Add vault profile export/import

This commit is contained in:
thePR0M3TH3AN
2025-07-18 16:05:00 -04:00
parent 876d98a785
commit 29690d7c7b
6 changed files with 85 additions and 35 deletions

View File

@@ -84,7 +84,9 @@ def load_doc_commands() -> list[str]:
cmds = set(re.findall(r"`seedpass ([^`<>]+)`", text))
cmds = {c for c in cmds if "<" not in c and ">" not in c}
cmds.discard("vault export")
cmds.discard("vault export --file backup.json")
cmds.discard("vault import")
cmds.discard("vault import --file backup.json")
return sorted(cmds)

View File

@@ -0,0 +1,33 @@
from pathlib import Path
from types import SimpleNamespace
from seedpass.core.api import VaultService
from helpers import create_vault, TEST_SEED, TEST_PASSWORD
def test_profile_export_import_round_trip(tmp_path):
dir1 = tmp_path / "a"
vault1, _ = create_vault(dir1, TEST_SEED, TEST_PASSWORD)
data = {
"schema_version": 4,
"entries": {"0": {"label": "example", "type": "password"}},
}
vault1.save_index(data)
pm1 = SimpleNamespace(vault=vault1, sync_vault=lambda: None)
service1 = VaultService(pm1)
blob = service1.export_profile()
dir2 = tmp_path / "b"
vault2, _ = create_vault(dir2, TEST_SEED, TEST_PASSWORD)
vault2.save_index({"schema_version": 4, "entries": {}})
called = {}
def sync():
called["synced"] = True
pm2 = SimpleNamespace(vault=vault2, sync_vault=sync)
service2 = VaultService(pm2)
service2.import_profile(blob)
assert called.get("synced") is True
assert vault2.load_index() == data

View File

@@ -68,58 +68,53 @@ def test_entry_get_password(monkeypatch):
def test_vault_export(monkeypatch, tmp_path):
called = {}
def export_db(path):
called["path"] = path
def export_profile(self):
called["export"] = True
return b"data"
pm = SimpleNamespace(
handle_export_database=export_db, select_fingerprint=lambda fp: None
)
monkeypatch.setattr(cli, "PasswordManager", lambda: pm)
monkeypatch.setattr(cli.VaultService, "export_profile", export_profile)
monkeypatch.setattr(cli, "PasswordManager", lambda: SimpleNamespace())
out_path = tmp_path / "out.json"
result = runner.invoke(app, ["vault", "export", "--file", str(out_path)])
assert result.exit_code == 0
assert called["path"] == out_path
assert called.get("export") is True
assert out_path.read_bytes() == b"data"
def test_vault_import(monkeypatch, tmp_path):
called = {}
def import_db(path):
called["path"] = path
def import_profile(self, data):
called["data"] = data
pm = SimpleNamespace(
handle_import_database=import_db,
select_fingerprint=lambda fp: None,
sync_vault=lambda: None,
)
monkeypatch.setattr(cli, "PasswordManager", lambda: pm)
monkeypatch.setattr(cli.VaultService, "import_profile", import_profile)
monkeypatch.setattr(cli, "PasswordManager", lambda: SimpleNamespace())
in_path = tmp_path / "in.json"
in_path.write_text("{}")
in_path.write_bytes(b"inp")
result = runner.invoke(app, ["vault", "import", "--file", str(in_path)])
assert result.exit_code == 0
assert called["path"] == in_path
assert called["data"] == b"inp"
def test_vault_import_triggers_sync(monkeypatch, tmp_path):
called = {}
def import_db(path):
called["path"] = path
def import_profile(self, data):
called["data"] = data
self._manager.sync_vault()
def sync():
def sync_vault():
called["sync"] = True
pm = SimpleNamespace(
handle_import_database=import_db,
sync_vault=sync,
select_fingerprint=lambda fp: None,
monkeypatch.setattr(cli.VaultService, "import_profile", import_profile)
monkeypatch.setattr(
cli, "PasswordManager", lambda: SimpleNamespace(sync_vault=sync_vault)
)
monkeypatch.setattr(cli, "PasswordManager", lambda: pm)
in_path = tmp_path / "in.json"
in_path.write_text("{}")
in_path.write_bytes(b"inp")
result = runner.invoke(app, ["vault", "import", "--file", str(in_path)])
assert result.exit_code == 0
assert called["path"] == in_path
assert called.get("data") == b"inp"
assert called.get("sync") is True