Download src/services.py from valent-p/qecho: direct link, hf CLI and curl.
- Browser
- Download file 4.93 kB
-
https://huggingface.co/spaces/valent-p/qecho/resolve/main/src/services.py
- Command line
-
hf download hf://spaces/valent-p/qecho/src/services.py
-
curl -L -o services.py https://huggingface.co/spaces/valent-p/qecho/resolve/main/src/services.py
4.93 kB
| import logging | |
| import sys | |
| from uuid import uuid4 | |
| import base64 | |
| from fastapi import HTTPException | |
| from cryptography.fernet import Fernet | |
| from src.database import supabase | |
| from src.security import generate_keys | |
| from src.models import PayloadRequest, RetrieveGroupRequest | |
| # --- LOGGING CONFIGURATION --- | |
| logger = logging.getLogger("qecho") | |
| logger.setLevel(logging.INFO) | |
| # Avoid adding duplicate handlers if re-imported | |
| if not logger.handlers: | |
| handler = logging.StreamHandler(sys.stdout) | |
| handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')) | |
| logger.addHandler(handler) | |
| # ----------------------------- | |
| async def process_store_data(payload: PayloadRequest): | |
| if not payload.data: | |
| raise HTTPException(status_code=400, detail="Data field is required") | |
| logger.info(f"Attempting to store data for group: {payload.group_name}") | |
| try: | |
| # 1. Generate Keys | |
| logger.info("Step 1: Generating Keys...") | |
| enc_key, db_index = generate_keys(payload.group_name, payload.password) | |
| logger.info(f"Keys generated. Blind Index hash: {db_index[:8]}...") | |
| # 2. Encrypt | |
| logger.info("Step 2: Encrypting payload...") | |
| f = Fernet(enc_key) | |
| encrypted_bytes = f.encrypt(payload.data.encode()) | |
| encrypted_string = base64.urlsafe_b64encode(encrypted_bytes).decode('utf-8') | |
| record_id = str(uuid4()) | |
| logger.info(f"Payload encrypted. Record ID: {record_id}") | |
| # 3. Save to Supabase using the Blind Index | |
| logger.info("Step 3: Inserting into Supabase...") | |
| data, count = supabase.table("secrets").insert({ | |
| "id": record_id, | |
| "encrypted_data": encrypted_string, | |
| "group_hash": db_index | |
| }).execute() | |
| logger.info("Supabase insert successful.") | |
| return {"status": "success", "uuid": record_id, "message": "Securely stored."} | |
| except Exception as e: | |
| logger.exception("CRITICAL ERROR during store_data:") | |
| # We can optionally expose the error detail to the user for debugging purposes | |
| # since this is a dev/security tool, but be careful not to leak secrets. | |
| raise HTTPException(status_code=500, detail=f"Save failed: {str(e)}") | |
| async def process_retrieve_data(payload: RetrieveGroupRequest): | |
| logger.info(f"Attempting to retrieve data for group: {payload.group_name} with limit {payload.limit}") | |
| try: | |
| # 1. Generate Keys | |
| logger.info("Step 1: Generating Keys...") | |
| enc_key, db_index = generate_keys(payload.group_name, payload.password) | |
| logger.info(f"Keys generated. Blind Index hash: {db_index[:8]}...") | |
| # 2. Fetch | |
| logger.info("Step 2: select from Supabase...") | |
| response = supabase.table("secrets") \ | |
| .select("id, encrypted_data, created_at") \ | |
| .eq("group_hash", db_index) \ | |
| .order("created_at", desc=True) \ | |
| .limit(payload.limit) \ | |
| .execute() | |
| if not response.data: | |
| logger.info("No records found for this group.") | |
| return {"messages": []} | |
| logger.info(f"Found {len(response.data)} records. Attempting decryption...") | |
| # 3. Decrypt | |
| f = Fernet(enc_key) | |
| decrypted_messages = [] | |
| ids_to_delete = [] # Keep track of what we successfully decrypted | |
| for row in response.data: | |
| try: | |
| enc_bytes = base64.urlsafe_b64decode(row['encrypted_data']) | |
| dec_msg = f.decrypt(enc_bytes).decode() | |
| decrypted_messages.append({ | |
| "id": row['id'], | |
| "timestamp": row['created_at'], | |
| "content": dec_msg | |
| }) | |
| # If decryption worked, mark for deletion | |
| ids_to_delete.append(row['id']) | |
| except Exception as decrypt_err: | |
| logger.warning(f"Failed to decrypt message {row['id']}: {decrypt_err}") | |
| continue | |
| logger.info(f"Successfully decrypted {len(decrypted_messages)} messages.") | |
| # 4. BURN AFTER READING (If requested) | |
| if payload.burn and ids_to_delete: | |
| logger.info(f"Burn requested. Deleting {len(ids_to_delete)} messages...") | |
| supabase.table("secrets").delete().in_("id", ids_to_delete).execute() | |
| logger.info("Burn complete.") | |
| # Append a meta-message so the user knows | |
| decrypted_messages.append({ | |
| "system_info": f"Securely burned {len(ids_to_delete)} messages from the server." | |
| }) | |
| return {"messages": decrypted_messages} | |
| except Exception as e: | |
| logger.exception("CRITICAL ERROR during retrieve_data:") | |
| raise HTTPException(status_code=500, detail=f"Retrieve failed: {str(e)}") | |