fixes global

This commit is contained in:
user committed 2025-08-08 09:14:18 +03:00
1 parent 13dc4f39c8
commit cad0f6aebe
64 files changed
+10379 -254

No files matched your search

+54
View File
@@ -0,0 +1,54 @@
from __future__ import annotations
import base64
import hashlib
import logging
from dataclasses import dataclass, field, asdict
from datetime import datetime
from typing import Optional
logger = logging.getLogger(__name__)
@dataclass
class ContentChunk:
"""
Модель чанка зашифрованного контента.
Все бинарные поля представлены в base64-строках для JSON-совместимости.
- chunk_hash: HEX(SHA-256(raw_encrypted_chunk_bytes)) — для дедупликации
- signature: base64-encoded Ed25519 подпись структуры чанка (детали в ChunkManager)
"""
chunk_id: str
content_id: str
chunk_index: int
chunk_hash: str # hex sha256(raw encrypted data)
encrypted_data: str # base64
signature: Optional[str] = None
created_at: str = field(default_factory=lambda: datetime.utcnow().isoformat())
def to_dict(self) -> dict:
return asdict(self)
@classmethod
def from_dict(cls, data: dict) -> "ContentChunk":
required = ["chunk_id", "content_id", "chunk_index", "chunk_hash", "encrypted_data"]
for f in required:
if f not in data:
raise ValueError(f"Missing required field in ContentChunk: {f}")
return cls(
chunk_id=data["chunk_id"],
content_id=data["content_id"],
chunk_index=int(data["chunk_index"]),
chunk_hash=data["chunk_hash"],
encrypted_data=data["encrypted_data"],
signature=data.get("signature"),
created_at=data.get("created_at") or datetime.utcnow().isoformat(),
)
def encrypted_bytes(self) -> bytes:
return base64.b64decode(self.encrypted_data)
@staticmethod
def compute_sha256_hex(buf: bytes) -> str:
return hashlib.sha256(buf).hexdigest()
@@ -0,0 +1,95 @@
"""
Модель данных EncryptedContent для хранения результата шифрования контента.
Полезно для сериализации, логирования и передачи между подсистемами uploader-bot.
"""
from __future__ import annotations
import base64
import json
import logging
from dataclasses import dataclass, field, asdict
from datetime import datetime
from typing import Any, Dict, Optional
logger = logging.getLogger(__name__)
@dataclass
class EncryptedContent:
"""
Универсальная переносимая модель зашифрованного контента.
Все бинарные поля хранятся в Base64 (строки), чтобы быть JSON-совместимыми.
"""
content_id: str
ciphertext_b64: str
nonce_b64: str
tag_b64: str
# Подпись и открытый ключ подписанта (Ed25519). Могут отсутствовать.
signature: Optional[str] = None
signer_pubkey: Optional[str] = None
# Пользовательские/системные метаданные (должны совпадать при верификации)
metadata: Dict[str, Any] = field(default_factory=dict)
# Служебная метка времени создания структуры
created_at: str = field(default_factory=lambda: datetime.utcnow().isoformat())
def to_dict(self) -> Dict[str, Any]:
"""
Сериализация в словарь (JSON-совместимый).
"""
data = asdict(self)
# Ничего дополнительно не преобразуем — все поля уже JSON-friendly
return data
def to_json(self) -> str:
"""
Сериализация в JSON-строку.
"""
payload = self.to_dict()
try:
return json.dumps(payload, ensure_ascii=False, sort_keys=True)
except Exception as e:
logger.error(f"EncryptedContent.to_json serialization error: {e}")
raise
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> "EncryptedContent":
"""
Десериализация из словаря.
"""
required = ["content_id", "ciphertext_b64", "nonce_b64", "tag_b64"]
for f in required:
if f not in data:
raise ValueError(f"Missing required field in EncryptedContent: {f}")
return cls(
content_id=data["content_id"],
ciphertext_b64=data["ciphertext_b64"],
nonce_b64=data["nonce_b64"],
tag_b64=data["tag_b64"],
signature=data.get("signature"),
signer_pubkey=data.get("signer_pubkey"),
metadata=data.get("metadata", {}) or {},
created_at=data.get("created_at") or datetime.utcnow().isoformat(),
)
@classmethod
def from_crypto_result(cls, crypto_result: Dict[str, Any]) -> "EncryptedContent":
"""
Удобный конструктор из результата ContentCipher.encrypt_content()
"""
return cls.from_dict(crypto_result)
# Вспомогательные методы для работы с бинарными данными (если необходимо)
def ciphertext_bytes(self) -> bytes:
return base64.b64decode(self.ciphertext_b64)
def nonce_bytes(self) -> bytes:
return base64.b64decode(self.nonce_b64)
def tag_bytes(self) -> bytes:
return base64.b64decode(self.tag_b64)