Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions server/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ async def _verify_firebase_id_token(token: str) -> FirebaseIDTokenData:
auth.InvalidIdTokenError,
auth.ExpiredIdTokenError,
auth.RevokedIdTokenError,
) as e:
):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid or expired token"
)
except auth.UserDisabledError as e:
except auth.UserDisabledError:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="User disabled"
)
except (ValueError, auth.CertificateFetchError, auth.FirebaseError) as e:
except (ValueError, auth.CertificateFetchError, auth.FirebaseError):
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Internal server error",
Expand Down
45 changes: 38 additions & 7 deletions server/fastapi_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import traceback
import logging
import asyncio
import re

from fastapi import FastAPI, Request, HTTPException, Depends, Header
from fastapi.middleware.cors import CORSMiddleware
Expand Down Expand Up @@ -81,21 +82,51 @@ def create_fastapi_app() -> FastAPI:
app = FastAPI()

# Configure CORS
# FastAPI CORSMiddleware doesn't support regex patterns, so we list all allowed origins
allowed_origins = [
"https://bitquant.io",
"https://www.bitquant.io",
# Localhost ports for development
"http://localhost:3000",
"http://localhost:3001",
"http://localhost:3002",
"http://localhost:4000",
"http://localhost:4200",
"http://localhost:5000",
"http://localhost:5173",
"http://localhost:8000",
"http://localhost:8080",
"http://localhost:8081",
"http://localhost:9000",
]

# Vercel preview deployments pattern (will be checked in custom middleware)
vercel_pattern = re.compile(r"^https://defi-chat-hub-git-[\w-]+-open-gradient\.vercel\.app$")

app.add_middleware(
CORSMiddleware,
allow_origins=[
"https://bitquant.io",
"https://www.bitquant.io",
r"^http://localhost:(3000|3001|3002|4000|4200|5000|5173|8000|8080|8081|9000)$",
r"^https://defi-chat-hub-git-[\w-]+-open-gradient\.vercel\.app$",
],
allow_origins=allowed_origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)

# Add Datadog metrics middleware
app.add_middleware(DatadogMetricsMiddleware)

# Add custom CORS check for Vercel preview deployments
# This middleware runs after CORSMiddleware to handle regex patterns
@app.middleware("http")
async def cors_vercel_middleware(request: Request, call_next):
origin = request.headers.get("origin")
if origin and vercel_pattern.match(origin):
response = await call_next(request)
response.headers["Access-Control-Allow-Origin"] = origin
response.headers["Access-Control-Allow-Credentials"] = "true"
response.headers["Access-Control-Allow-Methods"] = "*"
response.headers["Access-Control-Allow-Headers"] = "*"
return response
return await call_next(request)

# Initialize DynamoDB session
database_manager = DatabaseManager()
Expand Down
42 changes: 25 additions & 17 deletions server/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,32 @@


def verify_solana_signature(verify_request: SolanaVerifyRequest) -> str:
try:
public_key = b58decode(verify_request.address)
signature = b58decode(verify_request.signature)
message = verify_request.message.encode("utf-8")
"""Verify Solana signature and create Firebase custom token.

Args:
verify_request: Solana verification request containing address, signature, and message.

Returns:
Firebase custom token as string.

Raises:
ValueError: If signature verification fails or token creation fails.
"""
public_key = b58decode(verify_request.address)
signature = b58decode(verify_request.signature)
message = verify_request.message.encode("utf-8")

verify_key = VerifyKey(public_key)
verify_key.verify(message, signature)
verify_key = VerifyKey(public_key)
verify_key.verify(message, signature)

uid = f"wallet_{verify_request.address}"
custom_token = auth.create_custom_token(uid)
uid = f"wallet_{verify_request.address}"
custom_token = auth.create_custom_token(uid)

if isinstance(custom_token, bytes):
token_bytes = custom_token
elif isinstance(custom_token, str):
token_bytes = custom_token.encode("utf-8")
else:
token_bytes = str(custom_token).encode("utf-8")
if isinstance(custom_token, bytes):
token_bytes = custom_token
elif isinstance(custom_token, str):
token_bytes = custom_token.encode("utf-8")
else:
token_bytes = str(custom_token).encode("utf-8")

return token_bytes.decode("utf-8")
except Exception:
raise
return token_bytes.decode("utf-8")