Critical:
- rename nodes/ -> mp_nodes/, shared/ -> mp_shared/ to avoid shadowing
ComfyUI core's nodes.py via sys.path injection (root cause of v0.1.1
'nodes is not a package' startup failure)
- http_post now streams response and enforces 50MB cap mid-stream (DoS)
- AES key derivation: HKDF -> PBKDF2-HMAC-SHA256 600k iters + random salt
(work factor against weak-key brute force; ciphertext format changed)
- fs_mkdir/copy/move/delete confined to ComfyUI input/output/temp + ~ by
default; UTILITY_MEGAPACK_ALLOW_ARBITRARY_PATHS=1 to override
UX / correctness:
- combo settings now declare options array (themes dropdown was empty)
- LATENT default 1x4x8x8 zeros -> {} (avoids Flux/SD3 shape crashes)
- @op decorator rejects reserved widget names mode/theme at register time
- _pad_outputs docstring updated to match relaxed opaque-type behavior
96 lines
3.8 KiB
Python
96 lines
3.8 KiB
Python
"""Tests for the Crypto category."""
|
|
|
|
import hashlib
|
|
import hmac as _hmac
|
|
|
|
import pytest
|
|
|
|
from mp_nodes.programming import ProgrammingNode
|
|
|
|
|
|
def run(mode, **kwargs):
|
|
return ProgrammingNode().process(mode=mode, theme="(use pack default)", **kwargs)
|
|
|
|
|
|
class TestHashes:
|
|
def test_sha256_known(self):
|
|
# echo -n "hello" | sha256sum
|
|
assert run("hash_sha256", text="hello")[0] == \
|
|
"2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
|
|
|
|
def test_sha512_known(self):
|
|
expected = hashlib.sha512(b"hello").hexdigest()
|
|
assert run("hash_sha512", text="hello")[0] == expected
|
|
|
|
def test_md5_known(self):
|
|
# echo -n "abc" | md5sum
|
|
assert run("hash_md5", text="abc")[0] == "900150983cd24fb0d6963f7d28e17f72"
|
|
|
|
def test_blake2b_known(self):
|
|
expected = hashlib.blake2b(b"hello").hexdigest()
|
|
assert run("hash_blake2b", text="hello")[0] == expected
|
|
|
|
def test_empty_input(self):
|
|
# Empty SHA-256
|
|
assert run("hash_sha256", text="")[0] == \
|
|
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
|
|
|
|
|
class TestHmac:
|
|
def test_hmac_sign_matches_stdlib(self):
|
|
sig = run("hmac_sign", text="message", key="secret")[0]
|
|
expected = _hmac.new(b"secret", b"message", hashlib.sha256).hexdigest()
|
|
assert sig == expected
|
|
|
|
def test_hmac_verify_correct(self):
|
|
sig = run("hmac_sign", text="hello", key="key")[0]
|
|
assert run("hmac_verify", text="hello", key="key", expected_hex=sig)[3] is True
|
|
|
|
def test_hmac_verify_wrong_key(self):
|
|
sig = run("hmac_sign", text="hello", key="key1")[0]
|
|
assert run("hmac_verify", text="hello", key="key2", expected_hex=sig)[3] is False
|
|
|
|
def test_hmac_verify_wrong_text(self):
|
|
sig = run("hmac_sign", text="hello", key="key")[0]
|
|
assert run("hmac_verify", text="goodbye", key="key", expected_hex=sig)[3] is False
|
|
|
|
def test_hmac_verify_handles_garbage_expected(self):
|
|
# constant-time compare with a non-hex string returns False, no crash
|
|
assert run("hmac_verify", text="x", key="k", expected_hex="not-hex")[3] is False
|
|
|
|
|
|
class TestAES:
|
|
def test_aes_round_trip(self):
|
|
ct = run("aes_encrypt", plaintext="hello world", key="my-passphrase")[0]
|
|
pt = run("aes_decrypt", ciphertext_b64=ct, key="my-passphrase")[0]
|
|
assert pt == "hello world"
|
|
|
|
def test_aes_round_trip_unicode(self):
|
|
ct = run("aes_encrypt", plaintext="café 🎉", key="k")[0]
|
|
pt = run("aes_decrypt", ciphertext_b64=ct, key="k")[0]
|
|
assert pt == "café 🎉"
|
|
|
|
def test_aes_decrypt_wrong_key_raises(self):
|
|
ct = run("aes_encrypt", plaintext="secret", key="key1")[0]
|
|
with pytest.raises(RuntimeError):
|
|
run("aes_decrypt", ciphertext_b64=ct, key="key2")
|
|
|
|
def test_aes_decrypt_short_blob_raises(self):
|
|
with pytest.raises(RuntimeError, match="too short"):
|
|
run("aes_decrypt", ciphertext_b64="dGlueQ==", key="anything")
|
|
|
|
def test_aes_two_encrypts_differ_due_to_random_salt_and_nonce(self):
|
|
a = run("aes_encrypt", plaintext="same input", key="same key")[0]
|
|
b = run("aes_encrypt", plaintext="same input", key="same key")[0]
|
|
assert a != b
|
|
|
|
def test_aes_v0_1_x_format_rejected_with_clear_error(self):
|
|
"""Old HKDF-format ciphertexts (no salt prefix) are too short for the new layout."""
|
|
# 12-byte nonce + 16-byte tag minimum from the old format = 28 bytes;
|
|
# the new format expects salt[16] + nonce[12] + tag[16] = 44 bytes minimum.
|
|
# An old 28-byte ciphertext must fail with the clearer length error.
|
|
old_format = b"x" * 28
|
|
import base64
|
|
with pytest.raises(RuntimeError, match="too short"):
|
|
run("aes_decrypt", ciphertext_b64=base64.b64encode(old_format).decode(), key="any")
|