42Cummer commited on
Commit
5ac2764
·
verified ·
1 Parent(s): 64ac0c7

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -6
app.py CHANGED
@@ -1,6 +1,7 @@
1
  import subprocess
2
  import sys
3
  import os
 
4
 
5
  from fastapi import FastAPI, HTTPException, Request # type: ignore
6
  from fastapi.middleware.cors import CORSMiddleware # type: ignore
@@ -10,6 +11,36 @@ from slowapi.util import get_remote_address # type: ignore
10
  from slowapi.errors import RateLimitExceeded # type: ignore
11
  from compiler import ErasCompiler # type: ignore
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  # Initialize FastAPI and Rate Limiter
14
  app = FastAPI(title="ErasLang IDE Backend")
15
  limiter = Limiter(key_func=get_remote_address)
@@ -19,10 +50,10 @@ app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
19
  # SWE Best Practice: Enable CORS so your frontend can communicate with this API
20
  app.add_middleware(
21
  CORSMiddleware,
22
- allow_origins=["*"], # In production, replace with your frontend URL
23
  allow_credentials=True,
24
- allow_methods=["*"],
25
- allow_headers=["*"],
26
  )
27
 
28
  compiler = ErasCompiler()
@@ -30,22 +61,45 @@ compiler = ErasCompiler()
30
  class PerformanceRequest(BaseModel):
31
  code: str
32
  inputs: list[int] = []
 
33
 
34
  @app.get("/")
35
  @limiter.limit("20/minute")
36
  async def root(request: Request):
37
  return {"message": "ErasLang Stage is Live. Ready for the Performance?"}
38
 
 
 
 
 
 
 
 
 
39
  @app.post("/perform")
40
  @limiter.limit("10/minute")
41
  async def run_eraslang(request: Request, body: PerformanceRequest):
42
  """
43
  Main execution endpoint.
44
- 1. Transpiles ErasLang -> Python
45
- 2. Spawns worker.py subprocess
46
- 3. Returns results or errors
 
47
  """
48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  # --- Step 1: Transpilation ---
50
  try:
51
  # We ensure the compiler adds # ERAS_LINE_X comments for our worker
 
1
  import subprocess
2
  import sys
3
  import os
4
+ from pathlib import Path
5
 
6
  from fastapi import FastAPI, HTTPException, Request # type: ignore
7
  from fastapi.middleware.cors import CORSMiddleware # type: ignore
 
11
  from slowapi.errors import RateLimitExceeded # type: ignore
12
  from compiler import ErasCompiler # type: ignore
13
 
14
+ # Load secret from .env file or environment variable
15
+ def load_secret():
16
+ """Load the API secret from .env file or environment variable"""
17
+ # Try environment variable first (for production)
18
+ secret = os.getenv("SECRET_PASSWORD")
19
+
20
+ # If not in env, try reading from .env file (for local development)
21
+ if not secret:
22
+ env_path = Path(__file__).parent.parent / ".env"
23
+ if env_path.exists():
24
+ with open(env_path, 'r') as f:
25
+ for line in f:
26
+ line = line.strip()
27
+ if line and not line.startswith('#') and '=' in line:
28
+ key, value = line.split('=', 1)
29
+ if key.strip() == 'SECRET_PASSWORD':
30
+ secret = value.strip()
31
+ # Remove surrounding quotes if present
32
+ if (secret.startswith('"') and secret.endswith('"')) or \
33
+ (secret.startswith("'") and secret.endswith("'")):
34
+ secret = secret[1:-1]
35
+ break
36
+
37
+ if not secret:
38
+ raise ValueError("SECRET_PASSWORD must be set in environment variable or .env file")
39
+
40
+ return secret
41
+
42
+ API_SECRET = load_secret()
43
+
44
  # Initialize FastAPI and Rate Limiter
45
  app = FastAPI(title="ErasLang IDE Backend")
46
  limiter = Limiter(key_func=get_remote_address)
 
50
  # SWE Best Practice: Enable CORS so your frontend can communicate with this API
51
  app.add_middleware(
52
  CORSMiddleware,
53
+ allow_origins=["https://eras-lang-ide.vercel.app", "http://localhost:5173"],
54
  allow_credentials=True,
55
+ allow_methods=["GET", "POST", "OPTIONS"], # Only allow necessary HTTP methods
56
+ allow_headers=["Content-Type", "Authorization", "Accept", "X-Requested-With"],
57
  )
58
 
59
  compiler = ErasCompiler()
 
61
  class PerformanceRequest(BaseModel):
62
  code: str
63
  inputs: list[int] = []
64
+ password: str # Secret password for authentication (required)
65
 
66
  @app.get("/")
67
  @limiter.limit("20/minute")
68
  async def root(request: Request):
69
  return {"message": "ErasLang Stage is Live. Ready for the Performance?"}
70
 
71
+ @app.get("/health")
72
+ async def health():
73
+ """
74
+ Health check endpoint - no CORS restrictions, no rate limiting.
75
+ Useful for monitoring and testing the deployed backend.
76
+ """
77
+ return {"status": "healthy", "service": "ErasLang API"}
78
+
79
  @app.post("/perform")
80
  @limiter.limit("10/minute")
81
  async def run_eraslang(request: Request, body: PerformanceRequest):
82
  """
83
  Main execution endpoint.
84
+ 1. Validates secret password
85
+ 2. Transpiles ErasLang -> Python
86
+ 3. Spawns worker.py subprocess
87
+ 4. Returns results or errors
88
  """
89
 
90
+ # --- Step 0: Password Check (Always Required) ---
91
+ if not body.password:
92
+ raise HTTPException(
93
+ status_code=401,
94
+ detail="Unauthorized. Password is required."
95
+ )
96
+
97
+ if body.password != API_SECRET:
98
+ raise HTTPException(
99
+ status_code=401,
100
+ detail="Unauthorized. Invalid password."
101
+ )
102
+
103
  # --- Step 1: Transpilation ---
104
  try:
105
  # We ensure the compiler adds # ERAS_LINE_X comments for our worker