mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2025-09-07 06:48:52 +00:00
Merge pull request #689 from PR0M3TH3AN/codex/add-password-policy-config-options
Add password policy config options
This commit is contained in:
@@ -488,6 +488,16 @@ class ConfigService:
|
||||
"min_lowercase": ("set_min_lowercase", int),
|
||||
"min_digits": ("set_min_digits", int),
|
||||
"min_special": ("set_min_special", int),
|
||||
"include_special_chars": (
|
||||
"set_include_special_chars",
|
||||
lambda v: v.lower() in ("1", "true", "yes", "y", "on"),
|
||||
),
|
||||
"allowed_special_chars": ("set_allowed_special_chars", lambda v: v),
|
||||
"special_mode": ("set_special_mode", lambda v: v),
|
||||
"exclude_ambiguous": (
|
||||
"set_exclude_ambiguous",
|
||||
lambda v: v.lower() in ("1", "true", "yes", "y", "on"),
|
||||
),
|
||||
"quick_unlock": (
|
||||
"set_quick_unlock",
|
||||
lambda v: v.lower() in ("1", "true", "yes", "y", "on"),
|
||||
|
@@ -58,6 +58,10 @@ class ConfigManager:
|
||||
"min_lowercase": 2,
|
||||
"min_digits": 2,
|
||||
"min_special": 2,
|
||||
"include_special_chars": True,
|
||||
"allowed_special_chars": "",
|
||||
"special_mode": "standard",
|
||||
"exclude_ambiguous": False,
|
||||
"verbose_timing": False,
|
||||
}
|
||||
try:
|
||||
@@ -83,6 +87,10 @@ class ConfigManager:
|
||||
data.setdefault("min_lowercase", 2)
|
||||
data.setdefault("min_digits", 2)
|
||||
data.setdefault("min_special", 2)
|
||||
data.setdefault("include_special_chars", True)
|
||||
data.setdefault("allowed_special_chars", "")
|
||||
data.setdefault("special_mode", "standard")
|
||||
data.setdefault("exclude_ambiguous", False)
|
||||
data.setdefault("verbose_timing", False)
|
||||
|
||||
# Migrate legacy hashed_password.enc if present and password_hash is missing
|
||||
@@ -259,6 +267,10 @@ class ConfigManager:
|
||||
min_lowercase=int(cfg.get("min_lowercase", 2)),
|
||||
min_digits=int(cfg.get("min_digits", 2)),
|
||||
min_special=int(cfg.get("min_special", 2)),
|
||||
include_special_chars=bool(cfg.get("include_special_chars", True)),
|
||||
allowed_special_chars=cfg.get("allowed_special_chars") or None,
|
||||
special_mode=cfg.get("special_mode") or None,
|
||||
exclude_ambiguous=bool(cfg.get("exclude_ambiguous", False)),
|
||||
)
|
||||
|
||||
def set_min_uppercase(self, count: int) -> None:
|
||||
@@ -281,6 +293,30 @@ class ConfigManager:
|
||||
cfg["min_special"] = int(count)
|
||||
self.save_config(cfg)
|
||||
|
||||
def set_include_special_chars(self, enabled: bool) -> None:
|
||||
"""Persist whether special characters are allowed."""
|
||||
cfg = self.load_config(require_pin=False)
|
||||
cfg["include_special_chars"] = bool(enabled)
|
||||
self.save_config(cfg)
|
||||
|
||||
def set_allowed_special_chars(self, chars: str | None) -> None:
|
||||
"""Persist the set of allowed special characters."""
|
||||
cfg = self.load_config(require_pin=False)
|
||||
cfg["allowed_special_chars"] = chars or ""
|
||||
self.save_config(cfg)
|
||||
|
||||
def set_special_mode(self, mode: str) -> None:
|
||||
"""Persist the special character mode."""
|
||||
cfg = self.load_config(require_pin=False)
|
||||
cfg["special_mode"] = mode
|
||||
self.save_config(cfg)
|
||||
|
||||
def set_exclude_ambiguous(self, enabled: bool) -> None:
|
||||
"""Persist whether ambiguous characters are excluded."""
|
||||
cfg = self.load_config(require_pin=False)
|
||||
cfg["exclude_ambiguous"] = bool(enabled)
|
||||
self.save_config(cfg)
|
||||
|
||||
def set_quick_unlock(self, enabled: bool) -> None:
|
||||
"""Persist the quick unlock toggle."""
|
||||
cfg = self.load_config(require_pin=False)
|
||||
|
@@ -196,3 +196,43 @@ def test_nostr_retry_settings_round_trip():
|
||||
cfg_mgr.set_nostr_retry_delay(3.5)
|
||||
assert cfg_mgr.get_nostr_max_retries() == 5
|
||||
assert cfg_mgr.get_nostr_retry_delay() == 3.5
|
||||
|
||||
|
||||
def test_special_char_settings_round_trip():
|
||||
with TemporaryDirectory() as tmpdir:
|
||||
vault, _ = create_vault(Path(tmpdir), TEST_SEED, TEST_PASSWORD)
|
||||
cfg_mgr = ConfigManager(vault, Path(tmpdir))
|
||||
|
||||
cfg = cfg_mgr.load_config(require_pin=False)
|
||||
assert cfg["include_special_chars"] is True
|
||||
assert cfg["allowed_special_chars"] == ""
|
||||
assert cfg["special_mode"] == "standard"
|
||||
assert cfg["exclude_ambiguous"] is False
|
||||
|
||||
cfg_mgr.set_include_special_chars(False)
|
||||
cfg_mgr.set_allowed_special_chars("@$")
|
||||
cfg_mgr.set_special_mode("safe")
|
||||
cfg_mgr.set_exclude_ambiguous(True)
|
||||
|
||||
cfg2 = cfg_mgr.load_config(require_pin=False)
|
||||
assert cfg2["include_special_chars"] is False
|
||||
assert cfg2["allowed_special_chars"] == "@$"
|
||||
assert cfg2["special_mode"] == "safe"
|
||||
assert cfg2["exclude_ambiguous"] is True
|
||||
|
||||
|
||||
def test_password_policy_extended_fields():
|
||||
with TemporaryDirectory() as tmpdir:
|
||||
vault, _ = create_vault(Path(tmpdir), TEST_SEED, TEST_PASSWORD)
|
||||
cfg_mgr = ConfigManager(vault, Path(tmpdir))
|
||||
|
||||
cfg_mgr.set_include_special_chars(False)
|
||||
cfg_mgr.set_allowed_special_chars("()")
|
||||
cfg_mgr.set_special_mode("safe")
|
||||
cfg_mgr.set_exclude_ambiguous(True)
|
||||
|
||||
policy = cfg_mgr.get_password_policy()
|
||||
assert policy.include_special_chars is False
|
||||
assert policy.allowed_special_chars == "()"
|
||||
assert policy.special_mode == "safe"
|
||||
assert policy.exclude_ambiguous is True
|
||||
|
Reference in New Issue
Block a user