feat: Eingabeprüfung, Verschlüsselung und Zeitlimits
Strikte Validierung von Server, Freigabe, Pfaden und Mount-Optionen (Allowlist, gesperrte Zugangsdaten-Schlüssel), Fernet-Schlüssel mit 0600, Ed25519-Schlüsselerzeugung, Schwärzung von Geheimnissen und Dateizugriffe mit Zeitlimit in Daemon-Threads. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
278180c541
commit
689ddf0d94
@@ -0,0 +1,67 @@
|
||||
"""Fallstrick 7: Schlüsseldatei, Verschlüsselung, Schwärzung, SSH-Schlüssel."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import io
|
||||
import stat
|
||||
from pathlib import Path
|
||||
|
||||
import paramiko
|
||||
import pytest
|
||||
from cryptography.fernet import Fernet
|
||||
|
||||
from netmover.crypto import (
|
||||
REDACTED,
|
||||
SecretBox,
|
||||
SecretError,
|
||||
generate_ssh_keypair,
|
||||
load_or_create_key,
|
||||
redact,
|
||||
)
|
||||
|
||||
|
||||
def test_key_created_with_0600_and_reused(tmp_path: Path) -> None:
|
||||
path = tmp_path / "lib" / "secret.key"
|
||||
key1 = load_or_create_key(path)
|
||||
assert stat.S_IMODE(path.stat().st_mode) == 0o600
|
||||
assert load_or_create_key(path) == key1
|
||||
|
||||
|
||||
def test_key_mode_is_tightened(tmp_path: Path) -> None:
|
||||
path = tmp_path / "secret.key"
|
||||
path.write_bytes(Fernet.generate_key())
|
||||
path.chmod(0o644)
|
||||
load_or_create_key(path)
|
||||
assert stat.S_IMODE(path.stat().st_mode) == 0o600
|
||||
|
||||
|
||||
def test_invalid_key_file(tmp_path: Path) -> None:
|
||||
path = tmp_path / "secret.key"
|
||||
path.write_text("kaputt")
|
||||
path.chmod(0o600)
|
||||
with pytest.raises(SecretError):
|
||||
load_or_create_key(path)
|
||||
|
||||
|
||||
def test_roundtrip_and_wrong_key() -> None:
|
||||
box = SecretBox(Fernet.generate_key())
|
||||
token = box.encrypt("geheim")
|
||||
assert "geheim" not in token
|
||||
assert box.decrypt(token) == "geheim"
|
||||
with pytest.raises(SecretError, match=r"secret\.key"):
|
||||
SecretBox(Fernet.generate_key()).decrypt(token)
|
||||
|
||||
|
||||
def test_redact() -> None:
|
||||
text = "mount error: user scanner pw Sommer2026! failed (Sommer2026)"
|
||||
out = redact(text, ["Sommer2026!", "Sommer2026", None, ""])
|
||||
assert "Sommer2026" not in out
|
||||
assert out.count(REDACTED) == 2
|
||||
|
||||
|
||||
def test_ssh_keypair_usable_by_paramiko() -> None:
|
||||
private, public = generate_ssh_keypair("netmover@test")
|
||||
key = paramiko.Ed25519Key.from_private_key(io.StringIO(private))
|
||||
assert public.startswith("ssh-ed25519 ")
|
||||
assert public.split()[1] == key.get_base64()
|
||||
assert public.endswith(" netmover@test")
|
||||
Reference in New Issue
Block a user