linum / app.py
Rémy
Improvement
0694075
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
from pydantic import BaseModel
import subprocess
import shlex
import os
from fastapi import FastAPI, HTTPException, Request
app = FastAPI()
# Add CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # Allows all origins
allow_credentials=True,
allow_methods=["*"], # Allows all methods
allow_headers=["*"], # Allows all headers
)
# Mount the static files directory
app.mount("/static", StaticFiles(directory="static"), name="static")
ALLOWED_COMMANDS = {
'ls', 'cd', 'pwd', 'echo', 'cat', 'grep', 'find', 'touch', 'mkdir', 'rm', 'cp', 'mv'
}
class Command(BaseModel):
command: str
@app.post("/execute")
async def execute_command(command: Command, request: Request):
try:
# Get or create a session-specific directory
session = request.session
if 'working_dir' not in session:
session['working_dir'] = '/tmp/user_' + os.urandom(8).hex()
os.makedirs(session['working_dir'], exist_ok=True)
working_dir = session['working_dir']
# Parse the command to get the base command
base_command = shlex.split(command.command)[0]
# Check if the base command is allowed
if base_command not in ALLOWED_COMMANDS:
raise HTTPException(status_code=403, detail=f"Command '{base_command}' is not allowed")
# Handle 'cd' command specially
if base_command == 'cd':
new_dir = os.path.join(working_dir, shlex.split(command.command)[1])
if os.path.isdir(new_dir):
session['working_dir'] = new_dir
return {"output": "", "error": "", "returncode": 0, "currentDirectory": new_dir}
else:
return {"output": "", "error": "No such directory", "returncode": 1, "currentDirectory": working_dir}
# Execute the command in the controlled environment
result = subprocess.run(command.command, shell=True, capture_output=True, text=True, timeout=5, cwd=working_dir)
return {
"output": result.stdout,
"error": result.stderr,
"returncode": result.returncode,
"currentDirectory": working_dir
}
except subprocess.TimeoutExpired:
raise HTTPException(status_code=408, detail="Command execution timed out")
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/")
async def root():
return FileResponse('static/index.html')