old htb folders
This commit is contained in:
2023-08-29 21:53:22 +02:00
parent 62ab804867
commit 82b0759f1e
21891 changed files with 6277643 additions and 0 deletions

Binary file not shown.

View File

@@ -0,0 +1,14 @@
FROM python:3.6.9-alpine
RUN apk --update --upgrade add --no-cache gcc musl-dev jpeg-dev zlib-dev libffi-dev cairo-dev pango-dev gdk-pixbuf-dev
WORKDIR /app
ENV HOME /home/svc
ENV PATH /home/svc/.local/bin:${PATH}
RUN python -m pip install --upgrade pip --user svc
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
RUN pip install pydantic[email] pyjwt
EXPOSE 8000
COPY . .
CMD ["python3", "-m", "uvicorn", "app.main:app", "--reload", "--workers", "100", "--host", "0.0.0.0", "--port" ,"8000"]

View File

@@ -0,0 +1,25 @@
from fastapi import APIRouter, Depends
from app.api.utils import is_admin, is_logged
from app.api.models import backup
import os
router = APIRouter()
WORK_DIR = os.getenv('WORK_DIR', '/app')
DATABASE_URL = os.getenv('DATABASE_URL', 'postgresql://postgres:postgres@192.168.1.4/hello_fastapi_dev')
@router.get('/', dependencies=[Depends(is_logged), Depends(is_admin)],include_in_schema=False)
async def admin_funcs():
return {"admin_funcs":{"check db connection":"/check","backup the application": "/backup"}}
@router.get('/check',dependencies=[Depends(is_logged), Depends(is_admin)],include_in_schema=False)
async def check_connection():
return {"details": "Not implemented yet!"}
# Take a backup of the application
@router.post("/backup",dependencies=[Depends(is_logged), Depends(is_admin)],include_in_schema=False)
async def backup(payload: backup):
os.system(f'tar -c -f {str(payload.path)}/app_backkup.tar {str(WORK_DIR)} &')
return {"INFO": "Done!"}

View File

@@ -0,0 +1,39 @@
from app.api import crud
from app.api.models import userDB, userSchema
from app.api.utils import create_jwt, is_a_user
from .utils import *
from fastapi import APIRouter, HTTPException, Header, Path, FastAPI, Depends, Request
from typing import List
import os
router = APIRouter()
SECRET = os.getenv('SECRET')
# Login a user
@router.post('/login')
async def login(payload: userSchema):
global SECRET
success = await crud.login(payload)
if success is None:
raise HTTPException(status_code=403, detail="Not authorized!")
else:
return create_jwt(payload.username, payload.email)
# Signing up a new user
@router.post("/signup", response_model=userDB, status_code=201)
async def create_user(payload: userSchema):
user = await is_a_user(payload)
if user is None:
pass
else:
raise HTTPException(status_code=424, detail="User already exists! ")
user_id = await crud.create_user(payload)
res = {
"id" : user_id,
"email" : payload.email,
"username" : payload.username
}
return res

View File

@@ -0,0 +1,54 @@
from app.api.models import quoteSchema, userSchema
from app.db import quotes, database, users
import hashlib
# Quote crud
async def post(payload: quoteSchema):
query = quotes.insert().values(title=payload.title, description=payload.description)
return await database.execute(query=query)
async def get(id: int):
query = quotes.select().where(id == quotes.c.id)
return await database.fetch_one(query=query)
async def get_all():
query = quotes.select()
return await database.fetch_all(query=query)
async def put(id:int, payload=quoteSchema):
query = (
quotes.update().where(id == quotes.c.id).values(title=payload.title, description=payload.description)
.returning(quotes.c.id)
)
return await database.execute(query=query)
async def delete(id:int):
query = quotes.delete().where(id == quotes.c.id)
return await database.execute(query=query)
# User crud
async def get_user(id: int):
query = users.select().where(id == users.c.id)
return await database.fetch_one(query=query)
async def get_users():
query = users.select()
return await database.fetch_all(query=query)
async def create_user(payload: userSchema):
query = users.insert().values(email=payload.email, username=payload.username, password=hashlib.md5(str(payload.password).encode()).hexdigest())
return await database.execute(query=query)
async def login(payload: userSchema):
try:
query = users.select().where(payload.email == users.c.email, payload.username == users.c.username , hashlib.md5(str(payload.password).encode()).hexdigest() == users.c.password)
return await database.fetch_one(query=query)
except Exception as e:
return None

View File

@@ -0,0 +1,29 @@
from pydantic import BaseModel, Field, EmailStr
# Quote model
class quoteSchema(BaseModel):
title: str = Field(..., min_length=3, max_length=50) #additional validation for the inputs
description: str = Field(...,min_length=3, max_length=1500)
#
class quoteDB(quoteSchema):
id: int
# User model
class userSchema(BaseModel):
email: EmailStr
username: str = Field(...,min_length=5, max_length=50)
password: str = Field(...,min_length=8, max_length=50)
class userDB(BaseModel):
id: int
email: str
username: str
# Token model
class token(BaseModel):
token: str
# Backup data model
class backup(BaseModel):
path: str

View File

@@ -0,0 +1,57 @@
from app.api import crud
from .utils import is_logged, is_admin
from app.api.models import quoteDB, quoteSchema
from fastapi import APIRouter, HTTPException, Path, Depends ,FastAPI, Request, Header
from typing import List
router = APIRouter()
# Get all the quotes
@router.get("/", response_model=List[quoteDB], dependencies=[Depends(is_logged)])
async def read_all_quotes(request: Request):
return await crud.get_all()
# Add a quote
@router.post("/", response_model=quoteDB, status_code=201, dependencies=[Depends(is_logged), Depends(is_admin)])
async def create_quote(payload: quoteSchema,request: Request):
quote_id = await crud.post(payload)
response_object = {
"id": quote_id,
"title": payload.title,
"description": payload.description,
}
return response_object
# Get quote by id
@router.get("/{id}/", response_model=quoteDB, dependencies=[Depends(is_logged)])
async def read_quote(request: Request, id: int = Path(..., gt=0)):
quote = await crud.get(id)
if not quote:
raise HTTPException(status_code=404, detail="quote not found")
return quote
# Update quote
@router.put("/{id}/", response_model=quoteDB, dependencies=[Depends(is_logged), Depends(is_admin)])
async def update_quote(payload:quoteSchema,request: Request, id:int=Path(...,gt=0)): #Ensures the input is greater than 0
quote = await crud.get(id)
if not quote:
raise HTTPException(status_code=404, detail="quote not found")
quote_id = await crud.put(id, payload)
response_object = {
"id": quote_id,
"title": payload.title,
"description": payload.description
}
return response_object
# Delete quote
@router.delete("/{id}/", response_model=quoteDB, dependencies=[Depends(is_logged), Depends(is_admin)])
async def delete_quote(request: Request,id:int = Path(...,gt=0)):
quote = await crud.get(id)
if not quote:
raise HTTPException(status_code=404, detail="quote not found")
await crud.delete(id)
return quote

View File

@@ -0,0 +1,43 @@
from app.api import crud
from app.api.models import token, userDB, userSchema
from app.api.utils import is_admin, is_logged, is_a_user
from .utils import *
from fastapi import APIRouter, HTTPException, Header, Path, FastAPI, Depends, Request
from typing import List
import os
router = APIRouter()
SECRET = os.getenv('SECRET')
# List users
@router.get('/',response_model=List[userDB], status_code=201, dependencies=[Depends(is_logged), Depends(is_admin)])
async def get_users(request: Request):
return await crud.get_users()
# List user by id
@router.get('/{id}/',response_model=userDB, status_code=201, dependencies=[Depends(is_logged), Depends(is_admin)])
async def get_user_by_id(request: Request,id: int = Path(...,gt=0)):
user = await crud.get_user(id)
if not user:
raise HTTPException(status_code=404, detail="user not found")
return user
# Add a new user
@router.post("/add", response_model=userDB, status_code=201, dependencies=[Depends(is_logged), Depends(is_admin)])
async def create_user(payload: userSchema):
user = await is_a_user(payload)
if user is None:
pass
else:
raise HTTPException(status_code=424, detail="User already exists! ")
user_id = await crud.create_user(payload)
res = {
"id" : user_id,
"email" : payload.email,
"username" : payload.username
}
return res

View File

@@ -0,0 +1,54 @@
import jwt, os
from typing import Optional
from fastapi import Request, HTTPException, Header
from app.api.models import userSchema
from app.db import database, users
SECRET = os.getenv('SECRET', 'secret123')
ADMIN_USER = os.getenv('ADMIN_USER')
# Create the JWT
def create_jwt(username, email):
global SECRET
payload = {"username":username,"email":email}
token = jwt.encode(payload,str(SECRET),algorithm='HS256')
return token
# Verify the JWT
def verify_jwt(token):
try:
global SECRET
payload = jwt.decode(token, str(SECRET), algorithms=['HS256'])
return True, payload
except Exception as e:
raise e
return False, None
# Check if the user is an admin.
async def is_admin(Authorization: str = Header(...)):
global ADMIN_USER
_, payload = verify_jwt(Authorization)
if payload['username'] == str(ADMIN_USER):
return True
else:
raise HTTPException(status_code=403, detail="Only admin users can access this resource")
# Check if an user exists
async def is_a_user(payload: userSchema):
query = users.select().where(payload.username == users.c.username, payload.email == users.c.email)
return await database.execute(query=query)
# check the user is logged in
async def is_logged(Authorization: str = Header(...)):
logged, body = verify_jwt(Authorization)
query = users.select().where(body['username'] == users.c.username, body['email'] == users.c.email)
user = await database.execute(query=query)
if (logged) and (user is not None):
return True, "Logged in as " + body['username']
else:
raise HTTPException(status_code=401, detail="Unauthorized")

View File

View File

@@ -0,0 +1,37 @@
import os
from sqlalchemy import (Column, DateTime, Integer, String, Table, create_engine, MetaData)
from sqlalchemy.sql import func
from databases import Database
# Database url if none is passed the default one is used
DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://postgres:postgres@172.22.0.1/mentorquotes_db")
# SQLAlchemy for quotes
engine = create_engine(DATABASE_URL)
metadata = MetaData()
quotes = Table(
"quotes",
metadata,
Column("id", Integer, primary_key=True),
Column("title", String(50)),
Column("description", String(50)),
Column("created_date", DateTime, default=func.now(), nullable=False)
)
# SQLAlchemy for users
engine = create_engine(DATABASE_URL)
metadata = MetaData()
users = Table(
"users",
metadata,
Column("id", Integer, primary_key=True),
Column("email", String(50)),
Column("username", String(50)),
Column("password", String(128) ,nullable=False)
)
# Databases query builder
database = Database(DATABASE_URL)

View File

@@ -0,0 +1,52 @@
from fastapi import FastAPI, Request
from starlette.middleware.cors import CORSMiddleware
from app.api import quotes, admin, users, auth
from app.db import engine, metadata, database
metadata.create_all(engine)
app = FastAPI(
title="MentorQuotes",
description="Working towards helping people move forward",
version="0.0.1",
contact={
"name": "james",
"url": "http://mentorquotes.htb",
"email": "james@mentorquotes.htb",
}
)
origins = [
"http://localhost",
"http://localhost:8080",
"*"
]
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["DELETE", "GET", "POST", "PUT"],
allow_headers=["*"],
)
@app.on_event("startup")
async def startup():
await database.connect()
@app.on_event("shutdown")
async def shutdown():
await database.disconnect()
app.include_router(auth.router, prefix="/auth", tags=['Auth'])
app.include_router(users.router, prefix="/users", tags=['Users'])
app.include_router(quotes.router, prefix="/quotes", tags=["Quotes"])
app.include_router(admin.router,prefix='/admin', tags=['Admin'])

View File

@@ -0,0 +1,43 @@
anyio==3.3.4
asgiref==3.4.1
astroid==2.8.4
asyncpg==0.24.0
attrs==21.2.0
certifi==2021.10.8
chardet==4.0.0
charset-normalizer==2.0.7
click==8.0.3
databases==0.5.3
fastapi==0.70.0
greenlet==1.1.2
h11==0.12.0
httptools==0.3.0
idna==3.3
iniconfig==1.1.1
isort==5.10.0
lazy-object-proxy==1.6.0
mccabe==0.6.1
more-itertools==8.10.0
packaging==21.2
platformdirs==2.4.0
pluggy==1.0.0
psycopg2-binary==2.9.1
py==1.11.0
pydantic==1.8.2
pylint==2.11.1
pyparsing==2.4.7
pytest==6.2.5
requests==2.26.0
six==1.16.0
sniffio==1.2.0
SQLAlchemy==1.4.26
starlette==0.16.0
toml==0.10.2
typing-extensions==3.10.0.2
urllib3==1.26.7
uvicorn==0.15.0
uvloop==0.16.0
wcwidth==0.2.5
websockets==10.0
wrapt==1.13.3
pydantic==1.9.1

View File

@@ -0,0 +1,41 @@
anyio==3.3.4
asgiref==3.4.1
astroid==2.8.4
asyncpg==0.24.0
attrs==21.2.0
certifi==2021.10.8
chardet==4.0.0
charset-normalizer==2.0.7
click==8.0.3
databases==0.5.3
fastapi==0.70.0
greenlet==1.1.2
h11==0.12.0
httptools==0.3.0
idna==3.3
iniconfig==1.1.1
isort==5.10.0
lazy-object-proxy==1.6.0
mccabe==0.6.1
more-itertools==8.10.0
packaging==21.2
platformdirs==2.4.0
pluggy==1.0.0
psycopg2-binary==2.9.3
py==1.11.0
pylint==2.11.1
pyparsing==2.4.7
pytest==6.2.5
requests==2.26.0
six==1.16.0
sniffio==1.2.0
SQLAlchemy==1.4.26
starlette==0.16.0
toml==0.10.2
typing-extensions==3.10.0.2
urllib3==1.26.7
uvicorn==0.15.0
wcwidth==0.2.5
websockets==9.1
wrapt==1.13.3
pydantic==1.9.1