129 lines
4.2 KiB
Python
129 lines
4.2 KiB
Python
from __future__ import annotations
|
|
|
|
import base64
|
|
import hashlib
|
|
import hmac
|
|
import time
|
|
from unittest.mock import patch
|
|
|
|
from yuxi.channel.common.crypto import (
|
|
hmac_sha256_base64,
|
|
hmac_sha256_sign,
|
|
sha1_sorted_sign,
|
|
verify_hmac_digest,
|
|
verify_timestamp,
|
|
)
|
|
|
|
|
|
class TestHmacSha256Sign:
|
|
def test_sign_with_str_inputs(self):
|
|
secret = "secret"
|
|
message = "message"
|
|
expected = hmac.new(secret.encode("utf-8"), message.encode("utf-8"), hashlib.sha256).digest()
|
|
assert hmac_sha256_sign(secret, message) == expected
|
|
|
|
def test_sign_with_bytes_inputs(self):
|
|
secret = b"secret"
|
|
message = b"message"
|
|
expected = hmac.new(secret, message, hashlib.sha256).digest()
|
|
assert hmac_sha256_sign(secret, message) == expected
|
|
|
|
def test_sign_with_mixed_inputs(self):
|
|
secret = "secret"
|
|
message = b"message"
|
|
expected = hmac.new(secret.encode("utf-8"), message, hashlib.sha256).digest()
|
|
assert hmac_sha256_sign(secret, message) == expected
|
|
|
|
|
|
class TestHmacSha256Base64:
|
|
def test_base64_signature(self):
|
|
secret = "secret"
|
|
message = "message"
|
|
expected = base64.b64encode(hmac_sha256_sign(secret, message)).decode("utf-8")
|
|
assert hmac_sha256_base64(secret, message) == expected
|
|
|
|
def test_base64_signature_is_str(self):
|
|
result = hmac_sha256_base64("s", "m")
|
|
assert isinstance(result, str)
|
|
|
|
|
|
class TestVerifyHmacDigest:
|
|
def test_valid_bytes_signature(self):
|
|
secret = "secret"
|
|
message = "message"
|
|
signature = hmac_sha256_sign(secret, message)
|
|
assert verify_hmac_digest(secret, message, signature) is True
|
|
|
|
def test_valid_base64_string_signature(self):
|
|
secret = "secret"
|
|
message = "message"
|
|
signature = hmac_sha256_base64(secret, message)
|
|
assert verify_hmac_digest(secret, message, signature) is True
|
|
|
|
def test_invalid_signature(self):
|
|
secret = "secret"
|
|
message = "message"
|
|
assert verify_hmac_digest(secret, message, b"wrong") is False
|
|
|
|
def test_none_signature(self):
|
|
assert verify_hmac_digest("secret", "message", None) is False
|
|
|
|
def test_different_secret(self):
|
|
signature = hmac_sha256_sign("secret", "message")
|
|
assert verify_hmac_digest("other", "message", signature) is False
|
|
|
|
|
|
class TestSha1SortedSign:
|
|
def test_sorted_concatenation(self):
|
|
expected = hashlib.sha1("".join(sorted(["b", "a", "c"])).encode("utf-8")).hexdigest()
|
|
assert sha1_sorted_sign("a", "b", "c") == expected
|
|
|
|
def test_empty_parts(self):
|
|
assert sha1_sorted_sign() == hashlib.sha1(b"").hexdigest()
|
|
|
|
def test_single_part(self):
|
|
assert sha1_sorted_sign("only") == hashlib.sha1(b"only").hexdigest()
|
|
|
|
|
|
class TestVerifyTimestamp:
|
|
def test_valid_int_timestamp(self):
|
|
now = int(time.time())
|
|
assert verify_timestamp(now) is True
|
|
|
|
def test_valid_str_timestamp(self):
|
|
now = int(time.time())
|
|
assert verify_timestamp(str(now)) is True
|
|
|
|
def test_timestamp_within_tolerance(self):
|
|
now = 1000
|
|
with patch("time.time", return_value=now):
|
|
assert verify_timestamp(now) is True
|
|
assert verify_timestamp(now - 300) is True
|
|
assert verify_timestamp(now + 300) is True
|
|
|
|
def test_timestamp_outside_tolerance(self):
|
|
now = 1000
|
|
with patch("time.time", return_value=now):
|
|
assert verify_timestamp(now - 301) is False
|
|
assert verify_timestamp(now + 301) is False
|
|
|
|
def test_invalid_string_timestamp(self):
|
|
assert verify_timestamp("not-a-number") is False
|
|
|
|
def test_none_timestamp(self):
|
|
assert verify_timestamp(None) is False
|
|
|
|
def test_float_string_timestamp(self):
|
|
assert verify_timestamp("1234.5") is False
|
|
|
|
def test_custom_tolerance(self):
|
|
now = 1000
|
|
with patch("time.time", return_value=now):
|
|
assert verify_timestamp(now - 10, tolerance=10) is True
|
|
assert verify_timestamp(now - 11, tolerance=10) is False
|
|
|
|
def test_negative_timestamp(self):
|
|
now = 1000
|
|
with patch("time.time", return_value=now):
|
|
assert verify_timestamp(-1) is False
|