LogicGoInfotechSpaces commited on
Commit
5f4a2fe
·
1 Parent(s): 11d45f5

Add Bearer token authentication to all API endpoints

Browse files

- Added HTTPBearer authentication with password: logicgo_videoswap@153
- All API endpoints now require Authorization header with Bearer token
- Test endpoint /api/test remains public for verification
- Password can be set via API_PASSWORD environment variable

Files changed (1) hide show
  1. api_server.py +60 -13
api_server.py CHANGED
@@ -1,5 +1,6 @@
1
- from fastapi import FastAPI, File, UploadFile, HTTPException, BackgroundTasks
2
  from fastapi.middleware.cors import CORSMiddleware
 
3
  from pydantic import BaseModel
4
  from typing import Optional, List
5
  import os
@@ -22,6 +23,20 @@ from DeepFakeAI.processors.frame.modules import face_swapper as DF_FS
22
 
23
  app = FastAPI(title="Face Swap Video API", version="1.0.0")
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  # CORS middleware
26
  app.add_middleware(
27
  CORSMiddleware,
@@ -232,7 +247,10 @@ async def process_face_swap(job_id: str, source_image_path: str, target_video_pa
232
  # API Endpoints
233
 
234
  @app.post("/api/source-image", response_model=SourceImageResponse)
235
- async def upload_source_image(file: UploadFile = File(...)):
 
 
 
236
  """Upload and store source image in MongoDB"""
237
  if not file.content_type.startswith('image/'):
238
  raise HTTPException(status_code=400, detail="File must be an image")
@@ -265,7 +283,10 @@ async def upload_source_image(file: UploadFile = File(...)):
265
  raise HTTPException(status_code=500, detail=f"Error uploading source image: {str(e)}")
266
 
267
  @app.post("/api/target-video", response_model=TargetVideoResponse)
268
- async def upload_target_video(file: UploadFile = File(...)):
 
 
 
269
  """Upload and store target video in MongoDB"""
270
  if not file.content_type.startswith('video/'):
271
  raise HTTPException(status_code=400, detail="File must be a video")
@@ -298,7 +319,11 @@ async def upload_target_video(file: UploadFile = File(...)):
298
  raise HTTPException(status_code=500, detail=f"Error uploading target video: {str(e)}")
299
 
300
  @app.post("/api/face-swap", response_model=JobStatus)
301
- async def start_face_swap(request: FaceSwapRequest, background_tasks: BackgroundTasks):
 
 
 
 
302
  """Start face swap processing"""
303
  try:
304
  # Get source image and target video from MongoDB
@@ -341,7 +366,7 @@ async def start_face_swap(request: FaceSwapRequest, background_tasks: Background
341
  raise HTTPException(status_code=500, detail=f"Error starting face swap: {str(e)}")
342
 
343
  @app.get("/api/job/{job_id}", response_model=JobStatus)
344
- async def get_job_status(job_id: str):
345
  """Get job status"""
346
  job = await jobs_collection.find_one({"job_id": job_id})
347
  if not job:
@@ -361,7 +386,7 @@ async def get_job_status(job_id: str):
361
  )
362
 
363
  @app.get("/api/result-video/{result_video_id}")
364
- async def get_result_video(result_video_id: str):
365
  """Get result video file"""
366
  result = await result_videos_collection.find_one({"_id": ObjectId(result_video_id)})
367
  if not result:
@@ -377,7 +402,7 @@ async def get_result_video(result_video_id: str):
377
  )
378
 
379
  @app.get("/api/source-images", response_model=List[SourceImageResponse])
380
- async def list_source_images():
381
  """List all source images"""
382
  cursor = source_images_collection.find().sort("uploaded_at", -1)
383
  images = []
@@ -392,7 +417,7 @@ async def list_source_images():
392
  return images
393
 
394
  @app.get("/api/target-videos", response_model=List[TargetVideoResponse])
395
- async def list_target_videos():
396
  """List all target videos"""
397
  cursor = target_videos_collection.find().sort("uploaded_at", -1)
398
  videos = []
@@ -407,7 +432,7 @@ async def list_target_videos():
407
  return videos
408
 
409
  @app.get("/api/result-videos", response_model=List[ResultVideoResponse])
410
- async def list_result_videos():
411
  """List all result videos"""
412
  cursor = result_videos_collection.find().sort("created_at", -1)
413
  results = []
@@ -424,8 +449,8 @@ async def list_result_videos():
424
  return results
425
 
426
  @app.get("/api/health")
427
- async def api_health():
428
- """Health check endpoint with GPU status"""
429
  import onnxruntime
430
  available_providers = onnxruntime.get_available_providers()
431
  gpu_available = 'CUDAExecutionProvider' in available_providers
@@ -439,8 +464,30 @@ async def api_health():
439
 
440
  @app.get("/")
441
  async def root():
442
- """Health check endpoint"""
443
- return {"message": "Face Swap Video API is running", "version": "1.0.0"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
444
 
445
  if __name__ == "__main__":
446
  import uvicorn
 
1
+ from fastapi import FastAPI, File, UploadFile, HTTPException, BackgroundTasks, Depends, Security
2
  from fastapi.middleware.cors import CORSMiddleware
3
+ from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
4
  from pydantic import BaseModel
5
  from typing import Optional, List
6
  import os
 
23
 
24
  app = FastAPI(title="Face Swap Video API", version="1.0.0")
25
 
26
+ # Authentication
27
+ API_PASSWORD = os.getenv("API_PASSWORD", "logicgo_videoswap@153")
28
+ security = HTTPBearer()
29
+
30
+ def verify_api_key(credentials: HTTPAuthorizationCredentials = Security(security)):
31
+ """Verify API key from Bearer token"""
32
+ if credentials.credentials != API_PASSWORD:
33
+ raise HTTPException(
34
+ status_code=401,
35
+ detail="Invalid authentication credentials",
36
+ headers={"WWW-Authenticate": "Bearer"},
37
+ )
38
+ return credentials.credentials
39
+
40
  # CORS middleware
41
  app.add_middleware(
42
  CORSMiddleware,
 
247
  # API Endpoints
248
 
249
  @app.post("/api/source-image", response_model=SourceImageResponse)
250
+ async def upload_source_image(
251
+ file: UploadFile = File(...),
252
+ api_key: str = Depends(verify_api_key)
253
+ ):
254
  """Upload and store source image in MongoDB"""
255
  if not file.content_type.startswith('image/'):
256
  raise HTTPException(status_code=400, detail="File must be an image")
 
283
  raise HTTPException(status_code=500, detail=f"Error uploading source image: {str(e)}")
284
 
285
  @app.post("/api/target-video", response_model=TargetVideoResponse)
286
+ async def upload_target_video(
287
+ file: UploadFile = File(...),
288
+ api_key: str = Depends(verify_api_key)
289
+ ):
290
  """Upload and store target video in MongoDB"""
291
  if not file.content_type.startswith('video/'):
292
  raise HTTPException(status_code=400, detail="File must be a video")
 
319
  raise HTTPException(status_code=500, detail=f"Error uploading target video: {str(e)}")
320
 
321
  @app.post("/api/face-swap", response_model=JobStatus)
322
+ async def start_face_swap(
323
+ request: FaceSwapRequest,
324
+ background_tasks: BackgroundTasks,
325
+ api_key: str = Depends(verify_api_key)
326
+ ):
327
  """Start face swap processing"""
328
  try:
329
  # Get source image and target video from MongoDB
 
366
  raise HTTPException(status_code=500, detail=f"Error starting face swap: {str(e)}")
367
 
368
  @app.get("/api/job/{job_id}", response_model=JobStatus)
369
+ async def get_job_status(job_id: str, api_key: str = Depends(verify_api_key)):
370
  """Get job status"""
371
  job = await jobs_collection.find_one({"job_id": job_id})
372
  if not job:
 
386
  )
387
 
388
  @app.get("/api/result-video/{result_video_id}")
389
+ async def get_result_video(result_video_id: str, api_key: str = Depends(verify_api_key)):
390
  """Get result video file"""
391
  result = await result_videos_collection.find_one({"_id": ObjectId(result_video_id)})
392
  if not result:
 
402
  )
403
 
404
  @app.get("/api/source-images", response_model=List[SourceImageResponse])
405
+ async def list_source_images(api_key: str = Depends(verify_api_key)):
406
  """List all source images"""
407
  cursor = source_images_collection.find().sort("uploaded_at", -1)
408
  images = []
 
417
  return images
418
 
419
  @app.get("/api/target-videos", response_model=List[TargetVideoResponse])
420
+ async def list_target_videos(api_key: str = Depends(verify_api_key)):
421
  """List all target videos"""
422
  cursor = target_videos_collection.find().sort("uploaded_at", -1)
423
  videos = []
 
432
  return videos
433
 
434
  @app.get("/api/result-videos", response_model=List[ResultVideoResponse])
435
+ async def list_result_videos(api_key: str = Depends(verify_api_key)):
436
  """List all result videos"""
437
  cursor = result_videos_collection.find().sort("created_at", -1)
438
  results = []
 
449
  return results
450
 
451
  @app.get("/api/health")
452
+ async def api_health(api_key: str = Depends(verify_api_key)):
453
+ """Health check endpoint with GPU status (requires authentication)"""
454
  import onnxruntime
455
  available_providers = onnxruntime.get_available_providers()
456
  gpu_available = 'CUDAExecutionProvider' in available_providers
 
464
 
465
  @app.get("/")
466
  async def root():
467
+ """Root endpoint - shows API is running"""
468
+ return {
469
+ "message": "Face Swap Video API is running",
470
+ "version": "1.0.0",
471
+ "docs": "/docs",
472
+ "health": "/api/health"
473
+ }
474
+
475
+
476
+ # Test endpoint to verify API is accessible (no auth required for testing)
477
+ @app.get("/api/test")
478
+ async def test_endpoint():
479
+ """Test endpoint to verify API is running (public endpoint)"""
480
+ return {
481
+ "status": "ok",
482
+ "message": "API is accessible",
483
+ "authentication": "Bearer token required for all endpoints except /api/test",
484
+ "endpoints": {
485
+ "upload_source": "POST /api/source-image",
486
+ "upload_target": "POST /api/target-video",
487
+ "face_swap": "POST /api/face-swap",
488
+ "health": "GET /api/health"
489
+ }
490
+ }
491
 
492
  if __name__ == "__main__":
493
  import uvicorn