Files
utun2/tests/test_service_ids.py
T
evgeny abf342534f Encrypt P2P call media and validate service IDs
Require signed and encrypted call audio/video using static identity keys. Fix attachment service ID collisions and media download handle lifetime; isolate LAN tests and audit the shared service registry.
2026-10-21 15:06:27 +02:00

108 lines
4.9 KiB
Python

#!/usr/bin/env python3
"""Проверка общего реестра ETCP: значения, единственное объявление и таблица регистрации."""
import os
from pathlib import Path
import re
import unittest
ROOT = Path(__file__).resolve().parents[1]
HEADER = Path("src/transport_layer/etcp_api.h")
ID = r"ETCP_(?:RT_)?ID_[A-Z0-9_]+"
DEFINE = re.compile(r"^\s*#\s*define\s+(" + ID + r")\s+([^\n]+)", re.MULTILINE)
COMMENTS = re.compile(r'"(?:\\.|[^"\\])*"|\'(?:\\.|[^\'\\])*\'|/\*.*?\*/|//[^\n]*', re.DOTALL)
BIND = re.compile(r"\b(etcp_bind|etcp_unbind|merkle_sync_init|etcp_router_bind|etcp_router_unbind|"
r"etcp_router_require_crypto|etcp_router_set_receive_ready)\s*\([^,]+,\s*(" + ID + r"|0x[\da-fA-F]+|\d+)\b")
CALLBACK = re.compile(r"\b(api_bindings|router_bindings)\.callbacks\s*\[\s*(" + ID + r"|0x[\da-fA-F]+|\d+)\s*\]")
def code(text):
return COMMENTS.sub(lambda m: m[0] if m[0][0] in "\"'" else "\n" * m[0].count("\n"), text)
def registry(text):
ids, values, errors = {}, {}, []
for match in DEFINE.finditer(code(text)):
name, literal = match.groups()
if name in ids:
errors.append(f"{name}: repeated declaration")
try:
value = int(literal.strip(), 0)
except ValueError:
errors.append(f"{name}: expected a numeric literal, got {literal!r}")
continue
if not 0 <= value <= 255:
errors.append(f"{name}: ID {value} does not fit in one byte")
space = "router" if name.startswith("ETCP_RT_ID_") else "raw"
previous = values.get((space, value))
if previous:
errors.append(f"{space} ID {value:#04x}: {previous} conflicts with {name}")
ids[name] = value
values[space, value] = name
return ids, errors
def check_source(text, ids):
text = code(text)
errors = [f"{name}: declare only in {HEADER}" for name, _ in DEFINE.findall(text)]
errors += [f"{name}: missing from {HEADER}" for name in sorted(set(re.findall(ID, text)) - ids.keys())]
uses = [(m[1], m[2], m[1].startswith("etcp_router_")) for m in BIND.finditer(text)]
uses += [(m[1], m[2], m[1] == "router_bindings") for m in CALLBACK.finditer(text)]
for operation, name, routed in uses:
prefix = "ETCP_RT_ID_" if routed else "ETCP_ID_"
if not name.startswith(prefix):
errors.append(f"{operation}: {name} must use a declared {prefix} identifier")
return errors
def sources():
excluded = {"tdesktop-dev", "third_party", "zxing-cpp", "openssl", "libopus", "speexdsp", "SoundTouch"}
for tree in ("src", "lib", "tools"):
for directory, children, files in os.walk(ROOT / tree):
children[:] = sorted(name for name in children if not name.startswith((".", "build")) and name not in excluded)
for name in sorted(files):
path = Path(directory) / name
if path.suffix in {".c", ".h", ".cpp", ".hpp", ".cc", ".cxx"} and path != ROOT / HEADER:
yield path
class ServiceIdsTests(unittest.TestCase):
def test_separate_tables(self):
ids, errors = registry("#define ETCP_ID_A 1\n#define ETCP_RT_ID_B 1\n")
self.assertEqual(errors, [])
self.assertEqual(len(ids), 2)
def test_conflicting_values_and_names(self):
for text in ("#define ETCP_RT_ID_A 0x40\n#define ETCP_RT_ID_B 0x40\n",
"#define ETCP_ID_A 1\n#define ETCP_ID_A 2\n"):
self.assertTrue(registry(text)[1])
def test_range_and_alias(self):
for literal in ("-1", "256", "ETCP_ID_OTHER"):
self.assertTrue(registry(f"#define ETCP_ID_A {literal}\n")[1])
def test_wrong_binding_and_missing_declaration(self):
ids = {"ETCP_ID_A": 1, "ETCP_RT_ID_B": 2}
for text in ("etcp_bind(inst, ETCP_RT_ID_B, cb);", "etcp_router_bind(inst, ETCP_ID_A, cb);",
"inst->api_bindings.callbacks[ETCP_RT_ID_B](conn, packet);", "etcp_bind(inst, 7, cb);",
"inst->router_bindings.callbacks[0](conn, packet);",
"packet->cmd = ETCP_ID_MISSING;", "#define ETCP_ID_A 1\n"):
self.assertTrue(check_source(text, ids), text)
self.assertFalse(check_source("etcp_bind(inst, ETCP_ID_A, cb); etcp_router_bind(inst, ETCP_RT_ID_B, cb);", ids))
def test_repository(self):
ids, errors = registry((ROOT / HEADER).read_text())
self.assertTrue(ids, f"empty registry in {HEADER}")
checked = 0
for path in sources():
errors += [f"{path.relative_to(ROOT)}: {error}" for error in check_source(path.read_text(), ids)]
checked += 1
self.assertEqual(errors, [], "\n" + "\n".join(errors))
raw = sum(not name.startswith("ETCP_RT_ID_") for name in ids)
print(f"[INFO] service ID audit passed: raw={raw} router={len(ids) - raw} source_files={checked}", flush=True)
if __name__ == "__main__":
unittest.main()