File size: 5,555 Bytes
8ede856 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | """Tests for security fixes - cryptographic random number generation and SSL context."""
import os
import ssl
import sys
# Add project root to sys.path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
import pytest
def test_wecom_crypto_uses_secrets():
"""Test that WXBizJsonMsgCrypt uses secrets module instead of random."""
from astrbot.core.platform.sources.wecom_ai_bot.WXBizJsonMsgCrypt import Prpcrypt
# Create an instance and test that random string generation works
prpcrypt = Prpcrypt(b"test_key_32_bytes_long_value!")
# Generate multiple random strings and verify they are different and valid
random_strings = [prpcrypt.get_random_str() for _ in range(10)]
# All strings should be 16 bytes long
assert all(len(s) == 16 for s in random_strings)
# All strings should be different (extremely high probability with cryptographic random)
assert len(set(random_strings)) == 10
# All strings should be numeric when decoded
for s in random_strings:
decoded = s.decode()
assert decoded.isdigit()
assert 1000000000000000 <= int(decoded) <= 9999999999999999
def test_wecomai_utils_uses_secrets():
"""Test that wecomai_utils uses secrets module for random string generation."""
from astrbot.core.platform.sources.wecom_ai_bot.wecomai_utils import (
generate_random_string,
)
# Generate multiple random strings and verify they are different
random_strings = [generate_random_string(10) for _ in range(20)]
# All strings should be 10 characters long
assert all(len(s) == 10 for s in random_strings)
# All strings should be alphanumeric
for s in random_strings:
assert s.isalnum()
# All strings should be different (extremely high probability with cryptographic random)
assert len(set(random_strings)) >= 19 # Allow for 1 collision in 20 (very unlikely)
def test_azure_tts_signature_uses_secrets():
"""Test that Azure TTS signature generation uses secrets module."""
import asyncio
from astrbot.core.provider.sources.azure_tts_source import OTTSProvider
# Create a provider with test config
config = {
"OTTS_SKEY": "test_secret_key",
"OTTS_URL": "https://example.com/api/tts",
"OTTS_AUTH_TIME": "https://example.com/api/time",
}
async def test_nonce_generation():
async with OTTSProvider(config) as provider:
# Mock time sync to avoid actual API calls
provider.time_offset = 0
provider.last_sync_time = 9999999999
# Generate multiple signatures and extract nonces
signatures = []
for _ in range(10):
sig = await provider._generate_signature()
signatures.append(sig)
# Extract nonces (second field in signature format: timestamp-nonce-0-hash)
nonces = [sig.split("-")[1] for sig in signatures]
# All nonces should be 10 characters long
assert all(len(n) == 10 for n in nonces)
# All nonces should be alphanumeric (lowercase letters and digits)
for n in nonces:
assert all(c in "abcdefghijklmnopqrstuvwxyz0123456789" for c in n)
# All nonces should be different (cryptographic random ensures uniqueness)
assert len(set(nonces)) == 10
asyncio.run(test_nonce_generation())
def test_ssl_context_fallback_explicit():
"""Test that SSL context fallback is properly configured."""
# This test verifies the SSL context configuration
# We can't easily test the full io.py functions without network calls,
# but we can verify that ssl.CERT_NONE and check_hostname=False are valid settings
# Create a context similar to what's used in io.py
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
# Verify the settings are applied correctly
assert ssl_context.check_hostname is False
assert ssl_context.verify_mode == ssl.CERT_NONE
# This configuration should work but is intentionally insecure for fallback
# The actual code only uses this when certificate validation fails
def test_io_module_has_ssl_imports():
"""Verify that io.py properly imports ssl module."""
from astrbot.core.utils import io
# Check that ssl is available in the module
assert hasattr(io, "ssl")
# Check that CERT_NONE constant is accessible
assert hasattr(io.ssl, "CERT_NONE")
def test_secrets_module_randomness_quality():
"""Test that secrets module provides high-quality randomness."""
import secrets
# Generate a large set of random numbers
random_numbers = [secrets.randbelow(100) for _ in range(1000)]
# Basic statistical test: should have good distribution
unique_values = len(set(random_numbers))
# With 1000 random numbers from 0-99, we should see most values at least once
# This is a very basic test - real cryptographic random should pass this easily
assert unique_values >= 60 # Should see at least 60 different values out of 100
# Test secrets.choice for string generation
chars = "abcdefghijklmnopqrstuvwxyz0123456789"
random_chars = [secrets.choice(chars) for _ in range(1000)]
# Should have good character distribution
unique_chars = len(set(random_chars))
assert unique_chars >= 20 # Should see at least 20 different characters
if __name__ == "__main__":
pytest.main([__file__, "-v"])
|