mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2025-09-08 23:38:49 +00:00
Merge pull request #840 from PR0M3TH3AN/codex/increment-nostr-account-derivation
feat: track nostr account index per seed
This commit is contained in:
@@ -43,6 +43,7 @@ from seedpass.core.vault import Vault
|
|||||||
from seedpass.core.config_manager import ConfigManager
|
from seedpass.core.config_manager import ConfigManager
|
||||||
from seedpass.core.backup import BackupManager
|
from seedpass.core.backup import BackupManager
|
||||||
from seedpass.core.entry_management import EntryManager
|
from seedpass.core.entry_management import EntryManager
|
||||||
|
from seedpass.core.state_manager import StateManager
|
||||||
from nostr.client import NostrClient
|
from nostr.client import NostrClient
|
||||||
from utils.fingerprint import generate_fingerprint
|
from utils.fingerprint import generate_fingerprint
|
||||||
from utils.fingerprint_manager import FingerprintManager
|
from utils.fingerprint_manager import FingerprintManager
|
||||||
@@ -195,11 +196,13 @@ def main() -> None:
|
|||||||
|
|
||||||
encrypted = entry_mgr.vault.get_encrypted_index()
|
encrypted = entry_mgr.vault.get_encrypted_index()
|
||||||
if encrypted:
|
if encrypted:
|
||||||
|
idx = StateManager(dir_path).state.get("nostr_account_idx", 0)
|
||||||
client = NostrClient(
|
client = NostrClient(
|
||||||
entry_mgr.vault.encryption_manager,
|
entry_mgr.vault.encryption_manager,
|
||||||
fingerprint or dir_path.name,
|
fingerprint or dir_path.name,
|
||||||
parent_seed=seed,
|
parent_seed=seed,
|
||||||
config_manager=cfg_mgr,
|
config_manager=cfg_mgr,
|
||||||
|
account_index=idx,
|
||||||
)
|
)
|
||||||
asyncio.run(client.publish_snapshot(encrypted))
|
asyncio.run(client.publish_snapshot(encrypted))
|
||||||
print("[+] Data synchronized to Nostr.")
|
print("[+] Data synchronized to Nostr.")
|
||||||
|
@@ -58,6 +58,7 @@ class NostrClient(ConnectionHandler, SnapshotHandler):
|
|||||||
offline_mode: bool = False,
|
offline_mode: bool = False,
|
||||||
config_manager: Optional["ConfigManager"] = None,
|
config_manager: Optional["ConfigManager"] = None,
|
||||||
key_index: bytes | None = None,
|
key_index: bytes | None = None,
|
||||||
|
account_index: int | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.encryption_manager = encryption_manager
|
self.encryption_manager = encryption_manager
|
||||||
self.fingerprint = fingerprint
|
self.fingerprint = fingerprint
|
||||||
@@ -69,7 +70,7 @@ class NostrClient(ConnectionHandler, SnapshotHandler):
|
|||||||
parent_seed = self.encryption_manager.decrypt_parent_seed()
|
parent_seed = self.encryption_manager.decrypt_parent_seed()
|
||||||
|
|
||||||
# Use our project's KeyManager to derive the private key
|
# Use our project's KeyManager to derive the private key
|
||||||
self.key_manager = KeyManager(parent_seed, fingerprint)
|
self.key_manager = KeyManager(parent_seed, fingerprint, account_index)
|
||||||
|
|
||||||
# Create a nostr-sdk Keys object from our derived private key
|
# Create a nostr-sdk Keys object from our derived private key
|
||||||
private_key_hex = self.key_manager.keys.private_key_hex()
|
private_key_hex = self.key_manager.keys.private_key_hex()
|
||||||
|
@@ -16,17 +16,22 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class KeyManager:
|
class KeyManager:
|
||||||
"""
|
"""Manages key generation, encoding, and derivation for ``NostrClient``."""
|
||||||
Manages key generation, encoding, and derivation for NostrClient.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, parent_seed: str, fingerprint: str):
|
def __init__(
|
||||||
"""
|
self, parent_seed: str, fingerprint: str, account_index: int | None = None
|
||||||
Initializes the KeyManager with the provided parent_seed and fingerprint.
|
):
|
||||||
|
"""Initialize the key manager.
|
||||||
|
|
||||||
Parameters:
|
Parameters
|
||||||
parent_seed (str): The parent seed used for key derivation.
|
----------
|
||||||
fingerprint (str): The fingerprint to differentiate key derivations.
|
parent_seed:
|
||||||
|
The BIP-39 seed used as the root for derivations.
|
||||||
|
fingerprint:
|
||||||
|
Seed profile fingerprint used for legacy derivations and logging.
|
||||||
|
account_index:
|
||||||
|
Optional explicit index for BIP-85 Nostr key derivation. When ``None``
|
||||||
|
the index defaults to ``0``.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
if not isinstance(parent_seed, str):
|
if not isinstance(parent_seed, str):
|
||||||
@@ -40,12 +45,15 @@ class KeyManager:
|
|||||||
|
|
||||||
self.parent_seed = parent_seed
|
self.parent_seed = parent_seed
|
||||||
self.fingerprint = fingerprint
|
self.fingerprint = fingerprint
|
||||||
logger.debug(f"KeyManager initialized with parent_seed and fingerprint.")
|
self.account_index = account_index
|
||||||
|
logger.debug(
|
||||||
|
"KeyManager initialized with parent_seed, fingerprint and account index."
|
||||||
|
)
|
||||||
|
|
||||||
# Initialize BIP85
|
# Initialize BIP85
|
||||||
self.bip85 = self.initialize_bip85()
|
self.bip85 = self.initialize_bip85()
|
||||||
|
|
||||||
# Generate Nostr keys using the fingerprint
|
# Generate Nostr keys using the provided account index
|
||||||
self.keys = self.generate_nostr_keys()
|
self.keys = self.generate_nostr_keys()
|
||||||
logger.debug("Nostr Keys initialized successfully.")
|
logger.debug("Nostr Keys initialized successfully.")
|
||||||
|
|
||||||
@@ -70,34 +78,36 @@ class KeyManager:
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
def generate_nostr_keys(self) -> Keys:
|
def generate_nostr_keys(self) -> Keys:
|
||||||
"""
|
"""Derive a Nostr key pair using the configured ``account_index``."""
|
||||||
Derives a unique Nostr key pair for the given fingerprint using BIP-85.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Keys: An instance of Keys containing the Nostr key pair.
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
# Convert fingerprint to an integer index (using a hash function)
|
index = self.account_index if self.account_index is not None else 0
|
||||||
index = int(hashlib.sha256(self.fingerprint.encode()).hexdigest(), 16) % (
|
|
||||||
2**31
|
|
||||||
)
|
|
||||||
|
|
||||||
# Derive entropy for Nostr key (32 bytes)
|
|
||||||
entropy_bytes = self.bip85.derive_entropy(
|
entropy_bytes = self.bip85.derive_entropy(
|
||||||
index=index,
|
index=index, entropy_bytes=32, app_no=NOSTR_KEY_APP_ID
|
||||||
entropy_bytes=32,
|
|
||||||
app_no=NOSTR_KEY_APP_ID,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Generate Nostr key pair from entropy
|
|
||||||
private_key_hex = entropy_bytes.hex()
|
private_key_hex = entropy_bytes.hex()
|
||||||
keys = Keys(priv_k=private_key_hex)
|
keys = Keys(priv_k=private_key_hex)
|
||||||
logger.debug(f"Nostr keys generated for fingerprint {self.fingerprint}.")
|
logger.debug("Nostr keys generated for account index %s", index)
|
||||||
return keys
|
return keys
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to generate Nostr keys: {e}", exc_info=True)
|
logger.error(f"Failed to generate Nostr keys: {e}", exc_info=True)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
def generate_v1_nostr_keys(self) -> Keys:
|
||||||
|
"""Derive keys using the legacy fingerprint-hash method."""
|
||||||
|
try:
|
||||||
|
index = int(hashlib.sha256(self.fingerprint.encode()).hexdigest(), 16) % (
|
||||||
|
2**31
|
||||||
|
)
|
||||||
|
entropy_bytes = self.bip85.derive_entropy(
|
||||||
|
index=index, entropy_bytes=32, app_no=NOSTR_KEY_APP_ID
|
||||||
|
)
|
||||||
|
return Keys(priv_k=entropy_bytes.hex())
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to generate v1 Nostr keys: {e}", exc_info=True)
|
||||||
|
raise
|
||||||
|
|
||||||
def generate_legacy_nostr_keys(self) -> Keys:
|
def generate_legacy_nostr_keys(self) -> Keys:
|
||||||
"""Derive Nostr keys using the legacy application ID."""
|
"""Derive Nostr keys using the legacy application ID."""
|
||||||
try:
|
try:
|
||||||
|
@@ -296,6 +296,7 @@ class PasswordManager:
|
|||||||
self._suppress_entry_actions_menu: bool = False
|
self._suppress_entry_actions_menu: bool = False
|
||||||
self.last_bip85_idx: int = 0
|
self.last_bip85_idx: int = 0
|
||||||
self.last_sync_ts: int = 0
|
self.last_sync_ts: int = 0
|
||||||
|
self.nostr_account_idx: int = 0
|
||||||
self.auth_guard = AuthGuard(self)
|
self.auth_guard = AuthGuard(self)
|
||||||
|
|
||||||
# Service composition
|
# Service composition
|
||||||
@@ -1152,6 +1153,14 @@ class PasswordManager:
|
|||||||
print(colored("Please write this down and keep it in a safe place!", "red"))
|
print(colored("Please write this down and keep it in a safe place!", "red"))
|
||||||
|
|
||||||
if confirm_action("Do you want to use this generated seed? (Y/N): "):
|
if confirm_action("Do you want to use this generated seed? (Y/N): "):
|
||||||
|
# Determine next account index if state manager is available
|
||||||
|
next_idx = 0
|
||||||
|
if getattr(self, "state_manager", None) is not None:
|
||||||
|
try:
|
||||||
|
next_idx = self.state_manager.state.get("nostr_account_idx", 0) + 1
|
||||||
|
except Exception:
|
||||||
|
next_idx = 0
|
||||||
|
|
||||||
# Add a new fingerprint using the generated seed
|
# Add a new fingerprint using the generated seed
|
||||||
try:
|
try:
|
||||||
fingerprint = self.fingerprint_manager.add_fingerprint(new_seed)
|
fingerprint = self.fingerprint_manager.add_fingerprint(new_seed)
|
||||||
@@ -1184,6 +1193,15 @@ class PasswordManager:
|
|||||||
)
|
)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Persist the assigned account index for the new profile
|
||||||
|
try:
|
||||||
|
StateManager(fingerprint_dir).update_state(nostr_account_idx=next_idx)
|
||||||
|
if getattr(self, "state_manager", None) is not None:
|
||||||
|
self.state_manager.update_state(nostr_account_idx=next_idx)
|
||||||
|
self.nostr_account_idx = next_idx
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
# Set the current fingerprint in both PasswordManager and FingerprintManager
|
# Set the current fingerprint in both PasswordManager and FingerprintManager
|
||||||
self.current_fingerprint = fingerprint
|
self.current_fingerprint = fingerprint
|
||||||
self.fingerprint_manager.current_fingerprint = fingerprint
|
self.fingerprint_manager.current_fingerprint = fingerprint
|
||||||
@@ -1408,12 +1426,14 @@ class PasswordManager:
|
|||||||
self.last_sync_ts = state.get("last_sync_ts", 0)
|
self.last_sync_ts = state.get("last_sync_ts", 0)
|
||||||
self.manifest_id = state.get("manifest_id")
|
self.manifest_id = state.get("manifest_id")
|
||||||
self.delta_since = state.get("delta_since", 0)
|
self.delta_since = state.get("delta_since", 0)
|
||||||
|
self.nostr_account_idx = state.get("nostr_account_idx", 0)
|
||||||
else:
|
else:
|
||||||
relay_list = list(DEFAULT_RELAYS)
|
relay_list = list(DEFAULT_RELAYS)
|
||||||
self.last_bip85_idx = 0
|
self.last_bip85_idx = 0
|
||||||
self.last_sync_ts = 0
|
self.last_sync_ts = 0
|
||||||
self.manifest_id = None
|
self.manifest_id = None
|
||||||
self.delta_since = 0
|
self.delta_since = 0
|
||||||
|
self.nostr_account_idx = 0
|
||||||
self.offline_mode = bool(config.get("offline_mode", True))
|
self.offline_mode = bool(config.get("offline_mode", True))
|
||||||
self.inactivity_timeout = config.get(
|
self.inactivity_timeout = config.get(
|
||||||
"inactivity_timeout", INACTIVITY_TIMEOUT
|
"inactivity_timeout", INACTIVITY_TIMEOUT
|
||||||
@@ -1431,6 +1451,7 @@ class PasswordManager:
|
|||||||
config_manager=self.config_manager,
|
config_manager=self.config_manager,
|
||||||
parent_seed=getattr(self, "parent_seed", None),
|
parent_seed=getattr(self, "parent_seed", None),
|
||||||
key_index=self.KEY_INDEX,
|
key_index=self.KEY_INDEX,
|
||||||
|
account_index=self.nostr_account_idx,
|
||||||
)
|
)
|
||||||
|
|
||||||
if getattr(self, "manifest_id", None) and hasattr(
|
if getattr(self, "manifest_id", None) and hasattr(
|
||||||
@@ -4537,6 +4558,7 @@ class PasswordManager:
|
|||||||
config_manager=self.config_manager,
|
config_manager=self.config_manager,
|
||||||
parent_seed=getattr(self, "parent_seed", None),
|
parent_seed=getattr(self, "parent_seed", None),
|
||||||
key_index=self.KEY_INDEX,
|
key_index=self.KEY_INDEX,
|
||||||
|
account_index=self.nostr_account_idx,
|
||||||
)
|
)
|
||||||
|
|
||||||
if getattr(self, "manifest_id", None) and hasattr(
|
if getattr(self, "manifest_id", None) and hasattr(
|
||||||
|
@@ -21,6 +21,7 @@ from utils.key_derivation import (
|
|||||||
)
|
)
|
||||||
from .encryption import EncryptionManager
|
from .encryption import EncryptionManager
|
||||||
from utils.checksum import json_checksum, canonical_json_dumps
|
from utils.checksum import json_checksum, canonical_json_dumps
|
||||||
|
from .state_manager import StateManager
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -106,10 +107,12 @@ def export_backup(
|
|||||||
enc_file.write_bytes(encrypted)
|
enc_file.write_bytes(encrypted)
|
||||||
os.chmod(enc_file, 0o600)
|
os.chmod(enc_file, 0o600)
|
||||||
try:
|
try:
|
||||||
|
idx = StateManager(vault.fingerprint_dir).state.get("nostr_account_idx", 0)
|
||||||
client = NostrClient(
|
client = NostrClient(
|
||||||
vault.encryption_manager,
|
vault.encryption_manager,
|
||||||
vault.fingerprint_dir.name,
|
vault.fingerprint_dir.name,
|
||||||
config_manager=backup_manager.config_manager,
|
config_manager=backup_manager.config_manager,
|
||||||
|
account_index=idx,
|
||||||
)
|
)
|
||||||
asyncio.run(client.publish_snapshot(encrypted))
|
asyncio.run(client.publish_snapshot(encrypted))
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@@ -77,6 +77,7 @@ class ProfileService:
|
|||||||
config_manager=getattr(pm, "config_manager", None),
|
config_manager=getattr(pm, "config_manager", None),
|
||||||
parent_seed=getattr(pm, "parent_seed", None),
|
parent_seed=getattr(pm, "parent_seed", None),
|
||||||
key_index=pm.KEY_INDEX,
|
key_index=pm.KEY_INDEX,
|
||||||
|
account_index=pm.nostr_account_idx,
|
||||||
)
|
)
|
||||||
if getattr(pm, "manifest_id", None) and hasattr(
|
if getattr(pm, "manifest_id", None) and hasattr(
|
||||||
pm.nostr_client, "_state_lock"
|
pm.nostr_client, "_state_lock"
|
||||||
|
@@ -26,6 +26,7 @@ class StateManager:
|
|||||||
"manifest_id": None,
|
"manifest_id": None,
|
||||||
"delta_since": 0,
|
"delta_since": 0,
|
||||||
"relays": list(DEFAULT_RELAYS),
|
"relays": list(DEFAULT_RELAYS),
|
||||||
|
"nostr_account_idx": 0,
|
||||||
}
|
}
|
||||||
with shared_lock(self.state_path) as fh:
|
with shared_lock(self.state_path) as fh:
|
||||||
fh.seek(0)
|
fh.seek(0)
|
||||||
@@ -37,6 +38,7 @@ class StateManager:
|
|||||||
"manifest_id": None,
|
"manifest_id": None,
|
||||||
"delta_since": 0,
|
"delta_since": 0,
|
||||||
"relays": list(DEFAULT_RELAYS),
|
"relays": list(DEFAULT_RELAYS),
|
||||||
|
"nostr_account_idx": 0,
|
||||||
}
|
}
|
||||||
try:
|
try:
|
||||||
obj = json.loads(data.decode())
|
obj = json.loads(data.decode())
|
||||||
@@ -47,6 +49,7 @@ class StateManager:
|
|||||||
obj.setdefault("manifest_id", None)
|
obj.setdefault("manifest_id", None)
|
||||||
obj.setdefault("delta_since", 0)
|
obj.setdefault("delta_since", 0)
|
||||||
obj.setdefault("relays", list(DEFAULT_RELAYS))
|
obj.setdefault("relays", list(DEFAULT_RELAYS))
|
||||||
|
obj.setdefault("nostr_account_idx", 0)
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
def _save(self, data: dict) -> None:
|
def _save(self, data: dict) -> None:
|
||||||
|
@@ -20,6 +20,7 @@ def test_switch_fingerprint_triggers_bg_sync(monkeypatch, tmp_path):
|
|||||||
pm.current_fingerprint = None
|
pm.current_fingerprint = None
|
||||||
pm.encryption_manager = object()
|
pm.encryption_manager = object()
|
||||||
pm.config_manager = SimpleNamespace(get_quick_unlock=lambda: False)
|
pm.config_manager = SimpleNamespace(get_quick_unlock=lambda: False)
|
||||||
|
pm.nostr_account_idx = 0
|
||||||
|
|
||||||
monkeypatch.setattr("builtins.input", lambda *_a, **_k: "1")
|
monkeypatch.setattr("builtins.input", lambda *_a, **_k: "1")
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
|
@@ -5,6 +5,7 @@ from tempfile import TemporaryDirectory
|
|||||||
from seedpass.core.manager import PasswordManager
|
from seedpass.core.manager import PasswordManager
|
||||||
from utils.fingerprint_manager import FingerprintManager
|
from utils.fingerprint_manager import FingerprintManager
|
||||||
from utils.fingerprint import generate_fingerprint
|
from utils.fingerprint import generate_fingerprint
|
||||||
|
from seedpass.core.state_manager import StateManager
|
||||||
|
|
||||||
VALID_SEED = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
|
VALID_SEED = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
|
||||||
|
|
||||||
@@ -13,6 +14,7 @@ def setup_pm(tmp_path, monkeypatch):
|
|||||||
pm = PasswordManager.__new__(PasswordManager)
|
pm = PasswordManager.__new__(PasswordManager)
|
||||||
pm.fingerprint_manager = FingerprintManager(tmp_path)
|
pm.fingerprint_manager = FingerprintManager(tmp_path)
|
||||||
pm.config_manager = type("Cfg", (), {"get_kdf_iterations": lambda self: 1})()
|
pm.config_manager = type("Cfg", (), {"get_kdf_iterations": lambda self: 1})()
|
||||||
|
pm.state_manager = StateManager(tmp_path)
|
||||||
monkeypatch.setattr("seedpass.core.manager.prompt_for_password", lambda: "pw")
|
monkeypatch.setattr("seedpass.core.manager.prompt_for_password", lambda: "pw")
|
||||||
monkeypatch.setattr("seedpass.core.manager.derive_index_key", lambda seed: b"idx")
|
monkeypatch.setattr("seedpass.core.manager.derive_index_key", lambda seed: b"idx")
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
@@ -49,3 +51,5 @@ def test_generate_new_seed_creates_profile(monkeypatch):
|
|||||||
|
|
||||||
assert fingerprint == generate_fingerprint(VALID_SEED)
|
assert fingerprint == generate_fingerprint(VALID_SEED)
|
||||||
assert pm.fingerprint_manager.list_fingerprints() == [fingerprint]
|
assert pm.fingerprint_manager.list_fingerprints() == [fingerprint]
|
||||||
|
sm = StateManager(tmp_path / fingerprint)
|
||||||
|
assert sm.state["nostr_account_idx"] == 1
|
||||||
|
@@ -35,6 +35,7 @@ def test_change_password_triggers_nostr_backup(monkeypatch):
|
|||||||
pm.parent_seed = TEST_SEED
|
pm.parent_seed = TEST_SEED
|
||||||
pm.store_hashed_password = lambda pw: None
|
pm.store_hashed_password = lambda pw: None
|
||||||
pm.verify_password = lambda pw: True
|
pm.verify_password = lambda pw: True
|
||||||
|
pm.nostr_account_idx = 0
|
||||||
|
|
||||||
with patch("seedpass.core.manager.NostrClient") as MockClient:
|
with patch("seedpass.core.manager.NostrClient") as MockClient:
|
||||||
mock_instance = MockClient.return_value
|
mock_instance = MockClient.return_value
|
||||||
|
@@ -62,6 +62,7 @@ def test_password_change_and_unlock(monkeypatch):
|
|||||||
pm.nostr_client = SimpleNamespace(
|
pm.nostr_client = SimpleNamespace(
|
||||||
publish_snapshot=lambda *a, **k: (None, "abcd")
|
publish_snapshot=lambda *a, **k: (None, "abcd")
|
||||||
)
|
)
|
||||||
|
pm.nostr_account_idx = 0
|
||||||
|
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
"seedpass.core.manager.prompt_existing_password", lambda *_: old_pw
|
"seedpass.core.manager.prompt_existing_password", lambda *_: old_pw
|
||||||
|
@@ -20,6 +20,7 @@ def setup_pm(tmp_path):
|
|||||||
pm.encryption_mode = manager_module.EncryptionMode.SEED_ONLY
|
pm.encryption_mode = manager_module.EncryptionMode.SEED_ONLY
|
||||||
pm.fingerprint_manager = manager_module.FingerprintManager(constants.APP_DIR)
|
pm.fingerprint_manager = manager_module.FingerprintManager(constants.APP_DIR)
|
||||||
pm.current_fingerprint = None
|
pm.current_fingerprint = None
|
||||||
|
pm.state_manager = manager_module.StateManager(constants.APP_DIR)
|
||||||
return pm, constants, manager_module
|
return pm, constants, manager_module
|
||||||
|
|
||||||
|
|
||||||
@@ -41,8 +42,8 @@ def test_generate_seed_cleanup_on_failure(monkeypatch):
|
|||||||
|
|
||||||
# fingerprint list should be empty and only fingerprints.json should remain
|
# fingerprint list should be empty and only fingerprints.json should remain
|
||||||
assert pm.fingerprint_manager.list_fingerprints() == []
|
assert pm.fingerprint_manager.list_fingerprints() == []
|
||||||
contents = list(const.APP_DIR.iterdir())
|
contents = sorted(p.name for p in const.APP_DIR.iterdir())
|
||||||
assert len(contents) == 1 and contents[0].name == "fingerprints.json"
|
assert contents == ["fingerprints.json", "seedpass_state.json"]
|
||||||
fp_file = pm.fingerprint_manager.fingerprints_file
|
fp_file = pm.fingerprint_manager.fingerprints_file
|
||||||
with open(fp_file) as f:
|
with open(fp_file) as f:
|
||||||
data = json.load(f)
|
data = json.load(f)
|
||||||
|
@@ -29,6 +29,7 @@ def test_add_and_switch_fingerprint(monkeypatch):
|
|||||||
pm.fingerprint_manager = fm
|
pm.fingerprint_manager = fm
|
||||||
pm.encryption_manager = object()
|
pm.encryption_manager = object()
|
||||||
pm.current_fingerprint = None
|
pm.current_fingerprint = None
|
||||||
|
pm.nostr_account_idx = 0
|
||||||
|
|
||||||
monkeypatch.setattr("builtins.input", lambda *_args, **_kwargs: "1")
|
monkeypatch.setattr("builtins.input", lambda *_args, **_kwargs: "1")
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
|
@@ -21,6 +21,7 @@ def setup_password_manager():
|
|||||||
pm.fingerprint_manager = manager_module.FingerprintManager(constants.APP_DIR)
|
pm.fingerprint_manager = manager_module.FingerprintManager(constants.APP_DIR)
|
||||||
pm.current_fingerprint = None
|
pm.current_fingerprint = None
|
||||||
pm.save_and_encrypt_seed = lambda seed, fingerprint_dir: None
|
pm.save_and_encrypt_seed = lambda seed, fingerprint_dir: None
|
||||||
|
pm.state_manager = manager_module.StateManager(constants.APP_DIR)
|
||||||
return pm, constants
|
return pm, constants
|
||||||
|
|
||||||
|
|
||||||
|
@@ -120,6 +120,7 @@ def test_profile_service_switch(monkeypatch):
|
|||||||
pm.delta_since = None
|
pm.delta_since = None
|
||||||
pm.encryption_manager = SimpleNamespace()
|
pm.encryption_manager = SimpleNamespace()
|
||||||
pm.parent_seed = TEST_SEED
|
pm.parent_seed = TEST_SEED
|
||||||
|
pm.nostr_account_idx = 0
|
||||||
|
|
||||||
service = ProfileService(pm)
|
service = ProfileService(pm)
|
||||||
monkeypatch.setattr("builtins.input", lambda *_: "2")
|
monkeypatch.setattr("builtins.input", lambda *_: "2")
|
||||||
|
@@ -14,6 +14,7 @@ def test_state_manager_round_trip():
|
|||||||
assert state["last_sync_ts"] == 0
|
assert state["last_sync_ts"] == 0
|
||||||
assert state["manifest_id"] is None
|
assert state["manifest_id"] is None
|
||||||
assert state["delta_since"] == 0
|
assert state["delta_since"] == 0
|
||||||
|
assert state["nostr_account_idx"] == 0
|
||||||
|
|
||||||
sm.add_relay("wss://example.com")
|
sm.add_relay("wss://example.com")
|
||||||
sm.update_state(
|
sm.update_state(
|
||||||
@@ -30,6 +31,7 @@ def test_state_manager_round_trip():
|
|||||||
assert state2["last_sync_ts"] == 123
|
assert state2["last_sync_ts"] == 123
|
||||||
assert state2["manifest_id"] == "mid"
|
assert state2["manifest_id"] == "mid"
|
||||||
assert state2["delta_since"] == 111
|
assert state2["delta_since"] == 111
|
||||||
|
assert state2["nostr_account_idx"] == 0
|
||||||
|
|
||||||
sm2.remove_relay(1) # remove first default relay
|
sm2.remove_relay(1) # remove first default relay
|
||||||
assert len(sm2.list_relays()) == len(DEFAULT_RELAYS)
|
assert len(sm2.list_relays()) == len(DEFAULT_RELAYS)
|
||||||
|
Reference in New Issue
Block a user