|
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() |
|
|
|
|
|
app.add_middleware( |
|
CORSMiddleware, |
|
allow_origins=["*"], |
|
allow_credentials=True, |
|
allow_methods=["*"], |
|
allow_headers=["*"], |
|
) |
|
|
|
|
|
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: |
|
|
|
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'] |
|
|
|
|
|
base_command = shlex.split(command.command)[0] |
|
|
|
|
|
if base_command not in ALLOWED_COMMANDS: |
|
raise HTTPException(status_code=403, detail=f"Command '{base_command}' is not allowed") |
|
|
|
|
|
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} |
|
|
|
|
|
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') |