From 759bab3ff3345ff4e89cd8bcad03c265e4d7fa01 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Wed, 12 Jan 2022 07:48:18 +0000 Subject: [PATCH] Initial version --- Pipfile | 2 ++ app/auth.py | 32 +++++++++++++++++++-- app/file.py | 0 app/main.py | 37 ++++-------------------- app/server.py | 65 +++++++++++++++++++++++++++++++++++++++++++ app/test/test_main.py | 3 +- app/user.py | 14 ++++++++++ app/users.json | 2 +- 8 files changed, 118 insertions(+), 37 deletions(-) create mode 100644 app/file.py create mode 100644 app/server.py create mode 100644 app/user.py diff --git a/Pipfile b/Pipfile index 8a22574..73fe762 100644 --- a/Pipfile +++ b/Pipfile @@ -10,6 +10,8 @@ uvicorn = {extras = ["standard"], version = "*"} python-jose = {extras = ["cryptography"], version = "*"} passlib = "*" python-multipart = "*" +docker = "*" +aiodocker = "*" [dev-packages] pytest = "*" diff --git a/app/auth.py b/app/auth.py index b4908c3..a4049b4 100644 --- a/app/auth.py +++ b/app/auth.py @@ -3,11 +3,14 @@ import json from datetime import timedelta, datetime from typing import Optional from fastapi.security import OAuth2PasswordBearer -from fastapi import Depends, HTTPException, status +from fastapi import Depends, HTTPException, status, APIRouter from jose import JWTError, jwt from passlib.context import CryptContext -from app.models import User, UserInDB, TokenData +from app.models import User, UserInDB, TokenData, Token +from fastapi import Depends, HTTPException, status +from fastapi.security import OAuth2PasswordRequestForm +router = APIRouter() # to get a string like this run: # openssl rand -hex 32 @@ -78,4 +81,27 @@ async def get_current_user(token: str = Depends(oauth2_scheme)): async def get_current_active_user(current_user: User = Depends(get_current_user)): if current_user.disabled: raise HTTPException(status_code=400, detail="Inactive user") - return current_user \ No newline at end of file + return current_user + +def authorise(server, current_user: User = Depends(get_current_active_user)): + print(server, current_user.servers) + if server not in current_user.servers: + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED) + + + + +@router.post("/token", response_model=Token) +async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()): + user = authenticate_user(fake_users_db, form_data.username, form_data.password) + if not user: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Incorrect username or password", + headers={"WWW-Authenticate": "Bearer"}, + ) + access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) + access_token = create_access_token( + data={"sub": user.username}, expires_delta=access_token_expires + ) + return {"access_token": access_token, "token_type": "bearer"} diff --git a/app/file.py b/app/file.py new file mode 100644 index 0000000..e69de29 diff --git a/app/main.py b/app/main.py index 03ffc0a..9f209ab 100755 --- a/app/main.py +++ b/app/main.py @@ -1,35 +1,8 @@ -from datetime import timedelta - - -from fastapi import Depends, FastAPI, HTTPException, status -from fastapi.security import OAuth2PasswordRequestForm - -from app.models import Token, User -from app.auth import get_current_active_user, create_access_token, authenticate_user, fake_users_db, ACCESS_TOKEN_EXPIRE_MINUTES +from fastapi import FastAPI, Depends +from app import auth, user, server app = FastAPI() -@app.post("/token", response_model=Token) -async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()): - user = authenticate_user(fake_users_db, form_data.username, form_data.password) - if not user: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Incorrect username or password", - headers={"WWW-Authenticate": "Bearer"}, - ) - access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) - access_token = create_access_token( - data={"sub": user.username}, expires_delta=access_token_expires - ) - return {"access_token": access_token, "token_type": "bearer"} - - -@app.get("/users/me/", response_model=User) -async def read_users_me(current_user: User = Depends(get_current_active_user)): - return current_user - - -@app.get("/users/me/items/") -async def read_own_items(current_user: User = Depends(get_current_active_user)): - return [{"item_id": "Foo", "owner": current_user.username}] +app.include_router(auth.router) +app.include_router(user.router) +app.include_router(server.router, dependencies=[Depends(auth.authorise)]) diff --git a/app/server.py b/app/server.py new file mode 100644 index 0000000..ab5617b --- /dev/null +++ b/app/server.py @@ -0,0 +1,65 @@ +from fastapi import APIRouter, HTTPException, status, WebSocket +import base64 +import docker +import aiodocker + +router = APIRouter() +client = docker.from_env() +docker = aiodocker.Docker() + +@router.post("/server/{server}/start") +async def start(server): + try: + container = await getContainer(server) + await container.start() + except: + raise HTTPException(status_code=500) + return server + +@router.post("/server/{server}/stop") +async def stop(server): + try: + container = await getContainer(server) + await container.stop() + except: + raise HTTPException(status_code=500) + return server + +@router.post("/server/{server}/command/{command}", + description="Take server and base64 encoded command") +async def commnd(server, command): + try: + container = client.containers.get(server) + print(command) + cmd = base64.urlsafe_b64decode(command).decode('utf_8') + print(cmd) + container.exec_run(cmd="/usr/local/bin/cmd " + str(cmd)) + s= 200 + running="Success" + except: + raise HTTPException(status_code=500) + + return f"{server} {base64.urlsafe_b64decode(command).decode('utf_8')}" + + +@router.websocket("/server/{server}/logs") +async def logs(websocket: WebSocket, server: str): + await websocket.accept() + container = await getContainer(server) + async for line in container.log(stdout=True, follow=True, tail=5000): + #print(line) + await websocket.send_bytes(line) + print("Closed") + return server + +@router.get("/server/{server}/stats") +async def stats(websocket: WebSocket, server: str): + await websocket.accept() + container = await getContainer(server) + async for line in container.log(): + await websocket.send_bytes(line) + return server + + +async def getContainer(server): + return await docker.containers.get(server) \ No newline at end of file diff --git a/app/test/test_main.py b/app/test/test_main.py index cde0784..9f3c1df 100644 --- a/app/test/test_main.py +++ b/app/test/test_main.py @@ -8,7 +8,8 @@ from fastapi.testclient import TestClient from datetime import timedelta -from app.main import app, create_access_token +from app.main import app +from app.auth import create_access_token client = TestClient(app) diff --git a/app/user.py b/app/user.py new file mode 100644 index 0000000..99d8461 --- /dev/null +++ b/app/user.py @@ -0,0 +1,14 @@ +from fastapi import Depends, APIRouter +from app.models import User +from app.auth import get_current_active_user + +router = APIRouter() + +@router.get("/users/me/", response_model=User) +async def read_users_me(current_user: User = Depends(get_current_active_user)): + return current_user + + +@router.get("/users/me/items/") +async def read_own_items(current_user: User = Depends(get_current_active_user)): + return [{"item_id": "Foo", "owner": current_user.username}] diff --git a/app/users.json b/app/users.json index 068a03b..3e7afb3 100644 --- a/app/users.json +++ b/app/users.json @@ -5,6 +5,6 @@ "email": "johndoe@example.com", "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", "disabled": "False", - "servers": ["a", "b"] + "servers": ["a", "b","minecraft"] } } \ No newline at end of file