mirror of
https://github.com/fromchat-messenger/web.git
synced 2026-09-22 19:15:08 +03:00
Improve decryption error handling
This commit is contained in:
@@ -14,7 +14,9 @@ import time
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
import httpx
|
||||
from nacl.exceptions import CryptoError
|
||||
from fastapi import APIRouter, Depends, HTTPException, status, Request
|
||||
from sqlalchemy.orm import Session
|
||||
from pydantic import BaseModel, Field
|
||||
@@ -376,6 +378,20 @@ async def send_encrypted_message(
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except CryptoError as e:
|
||||
logger.warning(
|
||||
"DM send: transport NaCl decrypt failed (message/file key mismatch or corrupt ciphertext): %s",
|
||||
e,
|
||||
)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=(
|
||||
"Transport decryption failed: the encrypted message and each attachment must be "
|
||||
"encrypted with the same client ephemeral keypair. For resumable uploads, the "
|
||||
"ciphertext bytes on the server must match the transport fields in this request—"
|
||||
"re-encrypt on the client or abort the upload session and start over."
|
||||
),
|
||||
) from e
|
||||
except Exception as e:
|
||||
logger.exception("Error sending encrypted message: %s", e)
|
||||
raise HTTPException(
|
||||
|
||||
@@ -10,6 +10,9 @@ import os
|
||||
import logging
|
||||
import json
|
||||
|
||||
import httpx
|
||||
from fastapi import HTTPException, status
|
||||
|
||||
# Import request models for in-process calls
|
||||
|
||||
logger = logging.getLogger("uvicorn.error")
|
||||
@@ -418,11 +421,23 @@ async def process_message_with_files_in_messaging_service(
|
||||
"files": transport_files,
|
||||
}
|
||||
try:
|
||||
import httpx
|
||||
async with httpx.AsyncClient(timeout=timeout) as client:
|
||||
r = await client.post(url, json=payload)
|
||||
r.raise_for_status()
|
||||
return r.json()
|
||||
except httpx.HTTPStatusError as e:
|
||||
if e.response.status_code == status.HTTP_400_BAD_REQUEST:
|
||||
try:
|
||||
body = e.response.json()
|
||||
detail = body.get("detail", str(body)) if isinstance(body, dict) else str(body)
|
||||
except Exception:
|
||||
detail = (e.response.text or "").strip() or str(e)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=detail,
|
||||
) from e
|
||||
logger.error("Failed to process message+files in messaging service: %s", e)
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error("Failed to process message+files in messaging service: %s", e)
|
||||
raise
|
||||
|
||||
@@ -11,17 +11,21 @@ API Endpoints:
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sys
|
||||
import time
|
||||
import base64
|
||||
import os
|
||||
from typing import Dict, Any
|
||||
from fastapi import FastAPI, HTTPException, status
|
||||
from nacl.exceptions import CryptoError
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from contextlib import asynccontextmanager
|
||||
from pydantic import BaseModel
|
||||
|
||||
logger = logging.getLogger("uvicorn.error")
|
||||
|
||||
_B64_DECODE_KW = {"validate": True} if sys.version_info >= (3, 11) else {}
|
||||
|
||||
# Import encryption modules
|
||||
from .encryption import generate_nonce, TRANSPORT_NONCE_SIZE, decrypt_transport_blob, decrypt_transport_message
|
||||
from .processor import process_encrypted_message, process_encrypted_message_and_files
|
||||
@@ -371,16 +375,29 @@ async def process_message_with_files(
|
||||
|
||||
plaintext_files: list[bytes] = []
|
||||
filenames: list[str] = []
|
||||
for tf in transport_files:
|
||||
for idx, tf in enumerate(transport_files):
|
||||
enc_b64 = tf.get("encrypted_file_data_b64", "")
|
||||
transport_blob = base64.b64decode(enc_b64)
|
||||
plaintext_files.append(
|
||||
decrypt_transport_blob(
|
||||
client_public_key_b64=client_public_key_b64,
|
||||
encrypted_blob=transport_blob,
|
||||
ephemeral_private_key=private_key,
|
||||
try:
|
||||
transport_blob = base64.b64decode(enc_b64, **_B64_DECODE_KW)
|
||||
except Exception as e:
|
||||
logger.error("Invalid base64 for transport file index=%s filename=%r: %s", idx, tf.get("filename"), e)
|
||||
raise
|
||||
try:
|
||||
plaintext_files.append(
|
||||
decrypt_transport_blob(
|
||||
client_public_key_b64=client_public_key_b64,
|
||||
encrypted_blob=transport_blob,
|
||||
ephemeral_private_key=private_key,
|
||||
)
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
"Transport file decrypt failed index=%s filename=%r (check same ephemeral as message): %s",
|
||||
idx,
|
||||
tf.get("filename"),
|
||||
e,
|
||||
)
|
||||
raise
|
||||
filenames.append(tf.get("filename", "file"))
|
||||
|
||||
return process_encrypted_message_and_files(
|
||||
@@ -417,6 +434,15 @@ async def process_message_with_files_http(request: ProcessMessageWithFilesReques
|
||||
recipient_public_key_b64=request.recipient_public_key_b64,
|
||||
transport_files=transport_files,
|
||||
)
|
||||
except CryptoError as e:
|
||||
logger.warning("process-with-files: transport CryptoError: %s", e)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=(
|
||||
"Transport decryption failed: message and files must use the same client ephemeral "
|
||||
"key as when file ciphertext was produced."
|
||||
),
|
||||
) from e
|
||||
except Exception as e:
|
||||
logger.exception("Failed to process message with files: %s", e)
|
||||
raise
|
||||
|
||||
Reference in New Issue
Block a user