Architecture & Infrastructure
How CryptoCloud's backend is designed to handle encrypted file storage, secure sharing, and zero-knowledge guarantees at scale.
Tech Stack
Backend
- FastAPI 0.104+
- Python 3.13
- Uvicorn (ASGI)
- JWT Auth
Database
- MongoDB 6.0
- Motor (async ODM)
- 4 Collections
- Document Store
Storage
- AWS S3 / DO Spaces
- Pre-signed URLs
- boto3 SDK
- Direct Upload
Background
- Celery Workers
- Redis Broker
- Email Tasks
- Cleanup Jobs
System Overview
MongoDB Collections
users Collection
{
"_id": ObjectId,
"username": "alice", // Plaintext
"email": "alice@example.com", // Plaintext
"hashed_password": "bcrypt_hash", // bcrypt
"publicKey": "base64_spki", // RSA public (plaintext)
"encryptedPrivateKey": "base64string", // RSA private (encrypted)
"is_2fa_enabled": false,
"totp_secret": null,
"backup_codes": [],
"quota": 5368709120, // 5GB in bytes
"profile_picture_url": null
}files Collection
{
"_id": ObjectId,
"filename": "document.pdf", // Plaintext
"owner_id": ObjectId, // Reference to user
"upload_time": datetime, // UTC timestamp
"file_path": "uploads/uid/uuid", // S3 key
"file_size": 1048576, // Bytes (plaintext)
"isFolder": false,
"parentId": ObjectId | null, // Folder hierarchy
"encryptedFileKey": "base64string" // AES key (encrypted)
}shares Collection
{
"_id": ObjectId,
"owner_id": ObjectId,
"recipient_id": ObjectId,
"file_id": ObjectId,
"encryptedFileKey": "base64string", // Wrapped with RSA public key
"shared_at": datetime
}public_shares Collection
{
"_id": ObjectId,
"token": "random_32_byte_token",
"file_id": ObjectId,
"owner_id": ObjectId,
"filename": "document.pdf",
"file_size": 1048576,
"mime_type": "application/pdf",
"created_at": datetime,
"expires_at": datetime, // Auto-cleanup after 24h
"password_hash": "bcrypt_hash" | null,
"max_downloads": 10 | null,
"download_count": 0,
"is_active": true
}File Upload Pipeline
Client: Generate Random File Key
Browser generates a random 256-bit AES key unique to this file.
fileKey = crypto.subtle.generateKey("AES-GCM", 256)Client: Encrypt File Contents
File data encrypted with AES-256-GCM. Result includes IV, ciphertext, and authentication tag.
encryptedBlob = AES-GCM(fileKey, IV, fileData)Client: Encrypt File Key
File key encrypted with user's master key (never transmitted to server).
encryptedFileKey = AES-GCM(masterKey, IV, fileKey)Client → Server: Request Upload URL
POST to /files/request-upload-url with filename, size, content type.
POST /api/v1/files/request-upload-urlServer: Generate Pre-Signed S3 URL
Server checks quota, generates time-limited (5 min) pre-signed URL for direct S3 upload.
s3_client.generate_presigned_url("put_object", 300s)Client → S3: Upload Encrypted Blob
Client uploads encrypted blob directly to S3 (bypasses backend).
PUT https://s3.amazonaws.com/bucket/uploads/...Client → Server: Finalize Upload
POST to /files/finalize-upload with metadata + encrypted file key.
POST /api/v1/files/finalize-uploadServer: Store Metadata in MongoDB
Server creates file record with filename, size, S3 path, and encrypted file key.
db.files.insert_one(file_metadata)File Download Pipeline
Client → Server: Request Download URL
GET /files/download-url/:fileId
GET /api/v1/files/download-url/65a...Server: Verify Ownership & Generate URL
Server checks user owns file or has share access, generates 15-min pre-signed S3 URL.
Returns: { url: "s3_url", encryptedFileKey: "..." }Client → S3: Download Encrypted Blob
Client fetches encrypted blob directly from S3.
GET https://s3.amazonaws.com/bucket/uploads/...Client: Decrypt File Key
Browser decrypts file key using master key from memory.
fileKey = AES-GCM-Decrypt(masterKey, encryptedFileKey)Client: Decrypt File Contents
Browser decrypts blob with file key, triggers download.
fileData = AES-GCM-Decrypt(fileKey, encryptedBlob)Authentication Flow
Registration
- 1.Client derives master key: PBKDF2(password, 100k iterations)
- 2.Client generates RSA-4096 key pair
- 3.Client encrypts private key with master key
- 4.Server receives: username, email, password, public key, encrypted private key
- 5.Server hashes password with bcrypt, stores user record
Login
- 1.Client sends username + password to server
- 2.Server verifies bcrypt hash
- 3.If 2FA enabled: verify TOTP code
- 4.Server generates JWT (HS256), returns token + user data
- 5.Client derives master key locally, stores JWT in memory
Background Workers (Celery)
Cleanup Expired Shares
Frequency: Every 1 hour (cron)
Purpose: Delete public share links past expiration
db.public_shares.delete_many({ expires_at: { $lt: now } })Send Email Notifications
Trigger: Async on demand
Use Cases:
- • Login alerts (new device)
- • 2FA setup confirmation
- • Password reset (future)
Celery Configuration
Deployment & Infrastructure
Containerization
- • Docker + Docker Compose
- • backend: FastAPI + Uvicorn
- • celery-worker: Background tasks
- • database: MongoDB container
- • redis: Message broker
Production Hosting
- • Backend: Render.com
- • Frontend: Vercel
- • Storage: DigitalOcean Spaces (S3)
- • Database: MongoDB Atlas