gitscope
← marzneshin / Diff · c13a1aa → c13a1aa
Changes c13a1aa..c13a1aa
Patch commit
diff --git a/app/db/__init__.py b/app/db/__init__.py
index 67880dc..fc01894 100644
--- a/app/db/__init__.py
+++ b/app/db/__init__.py
@@ -1,11 +1,11 @@
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
-from sqlalchemy.schema import MetaData
from .base import Base, SessionLocal, engine # noqa
# meta_obj = MetaData()
+
class GetDB: # Context Manager
def __init__(self):
self.db = SessionLocal()
@@ -39,7 +39,6 @@ from .models import JWT, System, User # noqa
# meta_obj.create_all(engine)
__all__ = [
- "get_or_create_inbound",
"get_user",
"get_user_by_id",
"get_users",
diff --git a/app/dependencies.py b/app/dependencies.py
new file mode 100644
index 0000000..c63f416
--- /dev/null
+++ b/app/dependencies.py
@@ -0,0 +1,68 @@
+from typing import Annotated
+
+from fastapi import Depends, HTTPException, status
+from sqlalchemy.orm import Session
+
+from app.db import crud, get_db, User
+from app.models.admin import Admin, oauth2_scheme
+from app.utils.jwt import get_admin_payload
+from config import SUDOERS
+
+
+def get_admin(db: Annotated[Session, Depends(get_db)],
+ token: Annotated[str, Depends(oauth2_scheme)]):
+ payload = get_admin_payload(token)
+ if not payload:
+ return
+
+ if payload['username'] in SUDOERS and payload['is_sudo'] is True:
+ return Admin(username=payload['username'], is_sudo=True)
+
+ dbadmin = crud.get_admin(db, payload['username'])
+ if not dbadmin:
+ return
+
+ if dbadmin.password_reset_at:
+ if not payload.get("created_at"):
+ return
+ if dbadmin.password_reset_at > payload.get("created_at"):
+ return
+
+ return Admin.model_validate(dbadmin)
+
+
+def get_current_admin(admin: Annotated[Admin, Depends(get_admin)]):
+ if not admin:
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Could not validate credentials",
+ headers={"WWW-Authenticate": "Bearer"},
+ )
+
+ return admin
+
+
+def sudo_admin(admin: Annotated[Admin, Depends(get_current_admin)]):
+ if not admin.is_sudo:
+ raise HTTPException(
+ status_code=status.HTTP_403_FORBIDDEN,
+ detail="Access Denied",
+ )
+
+
+def get_current_user(username: str, key: str, db: Annotated[Session, Depends(get_db)]):
+ try:
+ int(key, 16)
+ except ValueError:
+ raise HTTPException(404)
+
+ db_user = crud.get_user(db, username)
+ if not db_user or db_user.key != key:
+ raise HTTPException(404)
+ return db_user
+
+
+SubUserDep = Annotated[User, Depends(get_current_user)]
+AdminDep = Annotated[Admin, Depends(get_current_admin)]
+SudoAdminDep = Annotated[Admin, Depends(sudo_admin)]
+DBDep = Annotated[Session, Depends(get_db)]
diff --git a/app/models/admin.py b/app/models/admin.py
index 2df71db..41e9982 100644
--- a/app/models/admin.py
+++ b/app/models/admin.py
@@ -1,14 +1,9 @@
from typing import Optional
-from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from passlib.context import CryptContext
from pydantic import ConfigDict, BaseModel
-from app.db import Session, crud, get_db
-from app.utils.jwt import get_admin_payload
-from config import SUDOERS
-
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/admin/token") # Admin view url
@@ -23,41 +18,6 @@ class Admin(BaseModel):
is_sudo: bool
model_config = ConfigDict(from_attributes=True)
- @classmethod
- def get_admin(cls, token: str, db: Session):
- payload = get_admin_payload(token)
- if not payload:
- return
-
- if payload['username'] in SUDOERS and payload['is_sudo'] is True:
- return cls(username=payload['username'], is_sudo=True)
-
- dbadmin = crud.get_admin(db, payload['username'])
- if not dbadmin:
- return
-
- if dbadmin.password_reset_at:
- if not payload.get("created_at"):
- return
- if dbadmin.password_reset_at > payload.get("created_at"):
- return
-
- return cls.from_orm(dbadmin)
-
- @classmethod
- def get_current(cls,
- db: Session = Depends(get_db),
- token: str = Depends(oauth2_scheme)):
- admin = cls.get_admin(token, db)
- if not admin:
- raise HTTPException(
- status_code=status.HTTP_401_UNAUTHORIZED,
- detail="Could not validate credentials",
- headers={"WWW-Authenticate": "Bearer"},
- )
-
- return admin
-
class AdminCreate(Admin):
password: str
diff --git a/app/utils/jwt.py b/app/utils/jwt.py
index aca1ad2..f238113 100644
--- a/app/utils/jwt.py
+++ b/app/utils/jwt.py
@@ -4,12 +4,12 @@ from typing import Union
from jose import JWTError, jwt
-from config import JWT_ACCESS_TOKEN_EXPIRE_MINUTES
+from config import JWT_ACCESS_TOKEN_EXPIRE_MINUTES, SUDOERS
+from app.db import GetDB, get_jwt_secret_key
@lru_cache(maxsize=None)
def get_secret_key():
- from app.db import GetDB, get_jwt_secret_key
with GetDB() as db:
return get_jwt_secret_key(db)
diff --git a/app/views/admin.py b/app/views/admin.py
index fce4cee..1d5a15f 100644
--- a/app/views/admin.py
+++ b/app/views/admin.py
@@ -1,10 +1,11 @@
-from typing import List, Optional
+from typing import List, Optional, Annotated
import sqlalchemy
from app import app
-from app.db import Session, crud, get_db
+from app.db import Session, crud
from app.models.admin import Admin, AdminCreate, AdminInDB, AdminModify, Token
from app.utils.jwt import create_admin_token
+from app.dependencies import AdminDep, SudoAdminDep, DBDep
from config import SUDOERS
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm
@@ -26,8 +27,8 @@ def authenticate_admin(db: Session, username: str, password: str) -> Optional[Ad
@app.post("/api/admin/token", tags=['Admin'], response_model=Token)
-def admin_token(form_data: OAuth2PasswordRequestForm = Depends(),
- db: Session = Depends(get_db)):
+def admin_token(form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
+ db: DBDep):
if authenticate_env_sudo(form_data.username, form_data.password):
return Token(access_token=create_admin_token(form_data.username, is_sudo=True))
@@ -43,12 +44,8 @@ def admin_token(form_data: OAuth2PasswordRequestForm = Depends(),
@app.post("/api/admin", tags=['Admin'], response_model=Admin)
def create_admin(new_admin: AdminCreate,
- db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
-
- if not admin.is_sudo:
- raise HTTPException(status_code=403, detail="You're not allowed")
-
+ db: DBDep,
+ admin: SudoAdminDep):
try:
dbadmin = crud.create_admin(db, new_admin)
except sqlalchemy.exc.IntegrityError:
@@ -61,8 +58,8 @@ def create_admin(new_admin: AdminCreate,
@app.put("/api/admin/{username}", tags=['Admin'], response_model=Admin)
def modify_admin(username: str,
modified_admin: AdminModify,
- db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
+ db: DBDep,
+ admin: AdminDep):
if not (admin.is_sudo or admin.username == username):
raise HTTPException(status_code=403, detail="You're not allowed")
@@ -78,7 +75,7 @@ def modify_admin(username: str,
if (username != admin.username) and dbadmin.is_sudo:
raise HTTPException(
status_code=403,
- detail=("You're not allowed to edit another sudoers account. Use marzban-cli instead.",),
+ detail="You're not allowed to edit another sudoers account. Use marzban-cli instead.",
)
dbadmin = crud.update_admin(db, dbadmin, modified_admin)
@@ -87,11 +84,8 @@ def modify_admin(username: str,
@app.delete("/api/admin/{username}", tags=['Admin'])
def remove_admin(username: str,
- db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
- if not admin.is_sudo:
- raise HTTPException(status_code=403, detail="You're not allowed")
-
+ db: DBDep,
+ admin: SudoAdminDep):
dbadmin = crud.get_admin(db, username)
if not dbadmin:
raise HTTPException(status_code=404, detail="Admin not found")
@@ -99,26 +93,22 @@ def remove_admin(username: str,
if dbadmin.is_sudo:
raise HTTPException(
status_code=403,
- detail=("You're not allowed to delete sudoers accounts. Use marzban-cli instead."),
+ detail="You're not allowed to delete sudoers accounts. Use marzban-cli instead.",
)
- dbadmin = crud.remove_admin(db, dbadmin)
+ crud.remove_admin(db, dbadmin)
return {}
@app.get("/api/admin", tags=["Admin"], response_model=Admin)
-def get_current_admin(admin: Admin = Depends(Admin.get_current)):
+def get_current_admin(admin: AdminDep):
return admin
@app.get("/api/admins", tags=['Admin'], response_model=List[Admin])
-def get_admins(offset: int = None,
+def get_admins(db: DBDep,
+ admin: SudoAdminDep,
+ offset: int = None,
limit: int = None,
- username: str = None,
- db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
-
- if not admin.is_sudo:
- raise HTTPException(status_code=403, detail="You're not allowed")
-
+ username: str = None):
return crud.get_admins(db, offset, limit, username)
diff --git a/app/views/node.py b/app/views/node.py
index 9220fff..a1b946f 100644
--- a/app/views/node.py
+++ b/app/views/node.py
@@ -4,23 +4,21 @@ from datetime import datetime
from typing import List
import sqlalchemy
-from fastapi import BackgroundTasks, Depends, HTTPException, WebSocket
+from fastapi import HTTPException, WebSocket
from app import app, logger, marznode
-from app.db import Session, crud, get_db, get_tls_certificate
+from app.db import crud, get_tls_certificate
from app.marznode import MarzNodeGRPC
from app.models.admin import Admin
from app.models.node import (NodeCreate, NodeModify, NodeResponse,
NodeSettings, NodeStatus, NodesUsageResponse)
+from app.dependencies import DBDep, SudoAdminDep
@app.get("/api/node/settings", tags=['Node'], response_model=NodeSettings)
-def get_node_settings(db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
- if not admin.is_sudo:
- raise HTTPException(status_code=403, detail="You're not allowed")
-
+def get_node_settings(db: DBDep,
+ admin: SudoAdminDep):
tls = crud.get_tls_certificate(db)
return NodeSettings(
@@ -30,12 +28,8 @@ def get_node_settings(db: Session = Depends(get_db),
@app.post("/api/node", tags=['Node'], response_model=NodeResponse)
async def add_node(new_node: NodeCreate,
- db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
-
- if not admin.is_sudo:
- raise HTTPException(status_code=403, detail="You're not allowed")
-
+ db: DBDep,
+ admin: SudoAdminDep):
try:
db_node = crud.create_node(db, new_node)
except sqlalchemy.exc.IntegrityError:
@@ -54,20 +48,19 @@ async def add_node(new_node: NodeCreate,
@app.get("/api/node/{node_id}", tags=['Node'], response_model=NodeResponse)
def get_node(node_id: int,
- db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
- if not admin.is_sudo:
- raise HTTPException(status_code=403, detail="You're not allowed")
-
- dbnode = crud.get_node_by_id(db, node_id)
- if not dbnode:
+ db: DBDep,
+ admin: SudoAdminDep):
+ db_node = crud.get_node_by_id(db, node_id)
+ if not db_node:
raise HTTPException(status_code=404, detail="Node not found")
- return dbnode
+ return db_node
@app.websocket("/api/node/{node_id}/logs")
-async def node_logs(node_id: int, websocket: WebSocket, db: Session = Depends(get_db)):
+async def node_logs(node_id: int,
+ websocket: WebSocket,
+ db: DBDep):
token = (
websocket.query_params.get('token')
or
@@ -101,22 +94,16 @@ async def node_logs(node_id: int, websocket: WebSocket, db: Session = Depends(ge
@app.get("/api/nodes", tags=['Node'], response_model=List[NodeResponse])
-def get_nodes(db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
- if not admin.is_sudo:
- raise HTTPException(status_code=403, detail="You're not allowed")
+def get_nodes(db: DBDep,
+ admin: SudoAdminDep):
return crud.get_nodes(db)
@app.put("/api/node/{node_id}", tags=['Node'], response_model=NodeResponse)
async def modify_node(node_id: int,
modified_node: NodeModify,
- db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
-
- if not admin.is_sudo:
- raise HTTPException(status_code=403, detail="You're not allowed")
-
+ db: DBDep,
+ admin: SudoAdminDep):
db_node = crud.get_node_by_id(db, node_id)
if not db_node:
raise HTTPException(status_code=404, detail="Node not found")
@@ -136,12 +123,8 @@ async def modify_node(node_id: int,
@app.post("/api/node/{node_id}/resync", tags=['Node'])
async def reconnect_node(node_id: int,
- db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
-
- if not admin.is_sudo:
- raise HTTPException(status_code=403, detail="You're not allowed")
-
+ db: DBDep,
+ admin: SudoAdminDep):
db_node = crud.get_node_by_id(db, node_id)
if not db_node:
raise HTTPException(status_code=404, detail="Node not found")
@@ -151,12 +134,8 @@ async def reconnect_node(node_id: int,
@app.delete("/api/node/{node_id}", tags=['Node'])
async def remove_node(node_id: int,
- db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
-
- if not admin.is_sudo:
- raise HTTPException(status_code=403, detail="You're not allowed")
-
+ db: DBDep,
+ admin: SudoAdminDep):
db_node = crud.get_node_by_id(db, node_id)
if not db_node:
raise HTTPException(status_code=404, detail="Node not found")
@@ -169,17 +148,13 @@ async def remove_node(node_id: int,
@app.get("/api/nodes/usage", tags=['Node'], response_model=NodesUsageResponse)
-def get_usage(db: Session = Depends(get_db),
+def get_usage(db: DBDep,
+ admin: SudoAdminDep,
start: str = None,
- end: str = None,
- admin: Admin = Depends(Admin.get_current)):
+ end: str = None):
"""
Get nodes usage
"""
-
- if not admin.is_sudo:
- raise HTTPException(status_code=403, detail="You're not allowed")
-
if start is None:
start_date = datetime.fromtimestamp(datetime.utcnow().timestamp() - 30 * 24 * 3600)
else:
diff --git a/app/views/service.py b/app/views/service.py
index d1af81d..52587ce 100644
--- a/app/views/service.py
+++ b/app/views/service.py
@@ -1,19 +1,19 @@
from typing import List
import sqlalchemy
-from fastapi import Depends, HTTPException
+from fastapi import HTTPException
from app import app
-from app.db import Session, crud, get_db
-from app.models.admin import Admin
+from app.db import crud
from app.models.service import (ServiceCreate, ServiceModify,
- ServiceResponse)
+ ServiceResponse)
+from app.dependencies import AdminDep, DBDep, SudoAdminDep
@app.post("/api/service", tags=['Service'], response_model=ServiceResponse)
def add_service(new_service: ServiceCreate,
- db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
+ db: DBDep,
+ admin: SudoAdminDep):
"""
Add a new user template
@@ -22,8 +22,6 @@ def add_service(new_service: ServiceCreate,
- **expire_duration** must be in seconds and larger or equat to 0
- **inbounds** dictionary of protocol:inbound_tags, empty means all inbounds
"""
- if not (admin.is_sudo):
- raise HTTPException(status_code=403, detail="You're not allowed")
try:
return crud.create_service(db, new_service)
except sqlalchemy.exc.IntegrityError:
@@ -32,7 +30,7 @@ def add_service(new_service: ServiceCreate,
@app.get("/api/service/{id}", tags=['Service'], response_model=ServiceResponse)
-def get_service(id: int, db: Session = Depends(get_db), admin: Admin = Depends(Admin.get_current)):
+def get_service(id: int, db: DBDep, admin: SudoAdminDep):
"""
Get Service information with id
"""
@@ -44,9 +42,10 @@ def get_service(id: int, db: Session = Depends(get_db), admin: Admin = Depends(A
@app.put("/api/service/{id}", tags=['Service'], response_model=ServiceResponse)
-def modify_service(id: int, modify_service: ServiceModify,
- db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
+def modify_service(id: int,
+ modify_service: ServiceModify,
+ db: DBDep,
+ admin: SudoAdminDep):
"""
Modify Service
@@ -59,7 +58,7 @@ def modify_service(id: int, modify_service: ServiceModify,
raise HTTPException(status_code=403, detail="You're not allowed")
dbservice = crud.get_service(db, id)
- if not dbuser_template:
+ if not dbservice:
raise HTTPException(status_code=404, detail="Service not found")
try:
@@ -71,20 +70,18 @@ def modify_service(id: int, modify_service: ServiceModify,
@app.delete("/api/service/{id}", tags=['Service'])
def remove_service(id: int,
- db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
- if not (admin.is_sudo):
- raise HTTPException(status_code=403, detail="You're not allowed")
-
+ db: DBDep,
+ admin: SudoAdminDep):
dbservice = crud.get_service(db, id)
- if not dbuser_template:
+ if not dbservice:
raise HTTPException(status_code=404, detail="Service not found")
return crud.remove_service(db, dbservice)
@app.get("/api/services", tags=['Service'], response_model=List[ServiceResponse])
-def get_services(
- offset: int = None, limit: int = None, db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
+def get_services(db: DBDep,
+ admin: AdminDep,
+ offset: int = None,
+ limit: int = None):
return crud.get_services(db) #, offset, limit)
diff --git a/app/views/subscription.py b/app/views/subscription.py
index 6b1d5b4..5e51165 100644
--- a/app/views/subscription.py
+++ b/app/views/subscription.py
@@ -1,11 +1,12 @@
import re
from datetime import datetime
-from fastapi import Depends, Header, HTTPException, Path, Request, Response
+from fastapi import Header, HTTPException, Path, Request, Response
from fastapi.responses import HTMLResponse
from app import app
-from app.db import Session, crud, get_db
+from app.db import crud
+from app.dependencies import DBDep, SubUserDep
from app.models.user import UserResponse
from app.templates import render_template
from app.utils.share import encode_title, generate_subscription
@@ -18,35 +19,27 @@ from config import (
)
+def get_subscription_user_info(user: UserResponse) -> dict:
+ return {
+ "upload": 0,
+ "download": user.used_traffic,
+ "total": user.data_limit,
+ "expire": user.expire,
+ }
+
+
@app.get("/%s/{username}/{key}/" % XRAY_SUBSCRIPTION_PATH, tags=['Subscription'])
@app.get("/%s/{username}/{key}" % XRAY_SUBSCRIPTION_PATH, include_in_schema=False)
-def user_subscription(username: str,
- key: str,
+def user_subscription(db_user: SubUserDep,
request: Request,
- db: Session = Depends(get_db),
+ db: DBDep,
user_agent: str = Header(default="")):
"""
Subscription link, V2ray and Clash supported
"""
accept_header = request.headers.get("Accept", "")
- def get_subscription_user_info(user: UserResponse) -> dict:
- return {
- "upload": 0,
- "download": user.used_traffic,
- "total": user.data_limit,
- "expire": user.expire,
- }
- try:
- int(key, 16)
- except ValueError:
- return Response(status_code=404)
-
- dbuser = crud.get_user(db, username)
- if not dbuser or dbuser.key != key:
- return Response(status_code=404)
-
- user: UserResponse = UserResponse.model_validate(dbuser)
+ user: UserResponse = UserResponse.model_validate(db_user)
if "text/html" in accept_header:
return HTMLResponse(
@@ -69,7 +62,7 @@ def user_subscription(username: str,
)
}
- crud.update_user_sub(db, dbuser, user_agent)
+ crud.update_user_sub(db, db_user, user_agent)
if re.match('^([Cc]lash-verge|[Cc]lash-?[Mm]eta)', user_agent):
conf = generate_subscription(user=user, config_format="clash-meta", as_base64=False)
@@ -93,36 +86,15 @@ def user_subscription(username: str,
@app.get("/%s/{username}/{key}/info" % XRAY_SUBSCRIPTION_PATH, tags=['Subscription'], response_model=UserResponse)
-def user_subscription_info(username: str,
- key: str,
- db: Session = Depends(get_db)):
- try:
- int(key, 16)
- except ValueError:
- return Response(status_code=404)
-
- dbuser = crud.get_user(db, username)
- if not dbuser or key != dbuser.key:
- return Response(status_code=404)
-
- return dbuser
+def user_subscription_info(db_user: SubUserDep):
+ return db_user
@app.get("/%s/{username}/{key}/usage" % XRAY_SUBSCRIPTION_PATH, tags=['Subscription'])
-def user_get_usage(username: str,
- key: str,
+def user_get_usage(db_user: SubUserDep,
+ db: DBDep,
start: str = None,
- end: str = None,
- db: Session = Depends(get_db)):
-
- try:
- int(key, 16)
- except ValueError:
- return Response(status_code=404)
-
- dbuser = crud.get_user(db, username)
- if not dbuser or key != dbuser.key:
- return Response(status_code=404)
+ end: str = None):
if start is None:
start_date = datetime.fromtimestamp(datetime.utcnow().timestamp() - 30 * 24 * 3600)
@@ -134,41 +106,21 @@ def user_get_usage(username: str,
else:
end_date = datetime.fromisoformat(end)
- usages = crud.get_user_usages(db, dbuser, start_date, end_date)
+ usages = crud.get_user_usages(db, db_user, start_date, end_date)
- return {"usages": usages, "username": dbuser.username}
+ return {"usages": usages, "username": db_user.username}
@app.get("/%s/{username}/{key}/{client_type}" % XRAY_SUBSCRIPTION_PATH, tags=['Subscription'])
def user_subscription_with_client_type(
- username: str,
- key: str,
+ db_user: SubUserDep,
request: Request,
- client_type: str = Path(..., regex="sing-box|clash-meta|clash|outline|v2ray"),
- db: Session = Depends(get_db),
-):
+ client_type: str = Path(..., regex="sing-box|clash-meta|clash|outline|v2ray")):
"""
Subscription link, v2ray, clash, sing-box, outline and clash-meta supported
"""
- def get_subscription_user_info(user: UserResponse) -> dict:
- return {
- "upload": 0,
- "download": user.used_traffic,
- "total": user.data_limit,
- "expire": user.expire,
- }
-
- try:
- int(key, 16)
- except ValueError:
- return Response(status_code=404)
-
- dbuser = crud.get_user(db, username)
- if not dbuser or key != dbuser.key:
- return Response(status_code=404)
-
- user: UserResponse = UserResponse.model_validate(dbuser)
+ user: UserResponse = UserResponse.model_validate(db_user)
response_headers = {
"content-disposition": f'attachment; filename="{user.username}"',
diff --git a/app/views/system.py b/app/views/system.py
index 9eadbab..2fab465 100644
--- a/app/views/system.py
+++ b/app/views/system.py
@@ -1,19 +1,18 @@
from typing import Dict, List, Union
-from fastapi import Depends, HTTPException
-
from app import app
-from app.db import Session, crud, get_db
+from app.db import crud
from app.models.admin import Admin
from app.models.proxy import InboundHost, Inbound, ProxyTypes, InboundBase
from app.models.system import SystemStats
from app.models.user import UserStatus
+from app.dependencies import DBDep, AdminDep, SudoAdminDep
from app.utils.system import memory_usage, cpu_usage, realtime_bandwidth
from app import __version__
@app.get("/api/system", tags=["System"], response_model=SystemStats)
-def get_system_stats(db: Session = Depends(get_db), admin: Admin = Depends(Admin.get_current)):
+def get_system_stats(db: DBDep, admin: AdminDep):
mem = memory_usage()
cpu = cpu_usage()
system = crud.get_system_usage(db)
@@ -39,43 +38,34 @@ def get_system_stats(db: Session = Depends(get_db), admin: Admin = Depends(Admin
@app.get('/api/inbounds', tags=["System"], response_model=List[Inbound])
-def get_inbounds(db: Session = Depends(get_db), admin: Admin = Depends(Admin.get_current)):
- inbounds = crud.get_all_inbounds(db)# xray.config.inbounds_by_protocol
- return inbounds
+def get_inbounds(db: DBDep, admin: SudoAdminDep):
+ inbounds = crud.get_all_inbounds(db)
+ return inbounds
@app.get('/api/hosts', tags=["System"], response_model=Dict[int, List[InboundHost]])
-def get_hosts(db: Session = Depends(get_db), admin: Admin = Depends(Admin.get_current)):
- if not admin.is_sudo:
- raise HTTPException(status_code=403, detail="You're not allowed")
-
- # hosts = {}
+def get_hosts(db: DBDep, admin: SudoAdminDep):
hosts = crud.get_all_hosts(db)
- #for inbound_tag in xray.config.inbounds_by_tag:
- # hosts[inbound_tag] = crud.get_hosts(db, inbound_tag)
return hosts
@app.put('/api/hosts', tags=["System"], response_model=Dict[str, List[InboundHost]])
def modify_hosts(modified_hosts: Dict[str, List[InboundHost]],
- db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
- if not admin.is_sudo:
- raise HTTPException(status_code=403, detail="You're not allowed")
-
+ db: DBDep,
+ admin: SudoAdminDep):
# validate
- #for inbound_id, hosts in modified_hosts.items():
- # if not xray.config.inbounds_by_id.get(inbound_id):
- # raise HTTPException(status_code=400, detail=f"Inbound {inbound_id} doesn't exist")
+ # for inbound_id, hosts in modified_hosts.items():
+ # if not xray.config.inbounds_by_id.get(inbound_id):
+ # raise HTTPException(status_code=400, detail=f"Inbound {inbound_id} doesn't exist")
for inbound_id, hosts in modified_hosts.items():
crud.update_hosts(db, inbound_id, hosts)
- #xray.hosts.update()
+ # xray.hosts.update()
hosts = {}
- #for inbound_tag in xray.config.inbounds_by_tag:
- # hosts[inbound_tag] = crud.get_hosts(db, inbound_tag)
+ # for inbound_tag in xray.config.inbounds_by_tag:
+ # hosts[inbound_tag] = crud.get_hosts(db, inbound_tag)
return hosts
diff --git a/app/views/user.py b/app/views/user.py
index 17a6e44..9baea3c 100644
--- a/app/views/user.py
+++ b/app/views/user.py
@@ -11,12 +11,13 @@ from app.models.admin import Admin
from app.models.user import (UserCreate, UserModify, UserResponse,
UsersResponse, UserStatus, UserUsagesResponse)
from app.utils import report
+from app.dependencies import get_current_admin, DBDep, AdminDep, SudoAdminDep
@app.post("/api/user", tags=['User'], response_model=UserResponse)
async def add_user(new_user: UserCreate,
- db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
+ db: DBDep,
+ admin: AdminDep):
"""
Add a new user
@@ -49,15 +50,15 @@ async def add_user(new_user: UserCreate,
@app.get("/api/user/{username}", tags=['User'], response_model=UserResponse)
def get_user(username: str,
- db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
+ db: DBDep,
+ admin: AdminDep):
"""
Get users information
"""
+ dbuser = crud.get_user(db, username)
if not (admin.is_sudo or (dbuser.admin and dbuser.admin.username == admin.username)):
raise HTTPException(status_code=403, detail="You're not allowed")
- dbuser = crud.get_user(db, username)
if not dbuser:
raise HTTPException(status_code=404, detail="User not found")
@@ -67,8 +68,8 @@ def get_user(username: str,
@app.put("/api/user/{username}", tags=['User'], response_model=UserResponse)
async def modify_user(username: str,
modified_user: UserModify,
- db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
+ db: DBDep,
+ admin: AdminDep):
"""
Modify a user
@@ -116,8 +117,8 @@ async def modify_user(username: str,
@app.delete("/api/user/{username}", tags=['User'])
async def remove_user(username: str,
- db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
+ db: DBDep,
+ admin: AdminDep):
"""
Remove a user
"""
@@ -144,8 +145,8 @@ async def remove_user(username: str,
@app.post("/api/user/{username}/reset", tags=['User'], response_model=UserResponse)
async def reset_user_data_usage(username: str,
- db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
+ db: DBDep,
+ admin: AdminDep):
"""
Reset user data usage
"""
@@ -174,8 +175,8 @@ async def reset_user_data_usage(username: str,
@app.post("/api/user/{username}/revoke_sub", tags=['User'], response_model=UserResponse)
async def revoke_user_subscription(username: str,
- db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
+ db: DBDep,
+ admin: AdminDep):
"""
Revoke users subscription (Subscription link and proxies)
"""
@@ -205,13 +206,13 @@ async def revoke_user_subscription(username: str,
@app.get("/api/users", tags=['User'], response_model=UsersResponse)
-def get_users(offset: int = None,
+def get_users(db: DBDep,
+ admin: AdminDep,
+ offset: int = None,
limit: int = None,
username: List[str] = Query(None),
status: UserStatus = None,
- sort: str = None,
- db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
+ sort: str = None):
"""
Get all users
"""
@@ -240,14 +241,11 @@ def get_users(offset: int = None,
@app.post("/api/users/reset", tags=['User'])
-async def reset_users_data_usage(db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
+async def reset_users_data_usage(db: DBDep,
+ admin: SudoAdminDep):
"""
Reset all users data usage
"""
- if not admin.is_sudo:
- raise HTTPException(status_code=403, detail="You're not allowed")
-
dbadmin = crud.get_admin(db, admin.username)
crud.reset_all_users_data_usage(db=db, admin=dbadmin)
# startup_config = xray.config.include_db_users()
@@ -259,11 +257,11 @@ async def reset_users_data_usage(db: Session = Depends(get_db),
@app.get("/api/user/{username}/usage", tags=['User'], response_model=UserUsagesResponse)
-def get_user_usage(username: str,
+def get_user_usage(db: DBDep,
+ admin: AdminDep,
+ username: str,
start: str = None,
- end: str = None,
- db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
+ end: str = None):
"""
Get users usage
"""
@@ -290,12 +288,8 @@ def get_user_usage(username: str,
@app.put("/api/user/{username}/set-owner", tags=['User'], response_model=UserResponse)
def set_owner(username: str,
admin_username: str,
- db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
-
- if not admin.is_sudo:
- raise HTTPException(status_code=403, detail="You're not allowed")
-
+ db: DBDep,
+ admin: SudoAdminDep):
dbuser = crud.get_user(db, username)
if not dbuser:
raise HTTPException(status_code=404, detail="User not found")
@@ -314,8 +308,8 @@ def set_owner(username: str,
@app.delete("/api/users/expired", tags=['User'])
def delete_expired(passed_time: int,
- db: Session = Depends(get_db),
- admin: Admin = Depends(Admin.get_current)):
+ db: DBDep,
+ admin: AdminDep):
"""
Delete expired users
- **passed_time** must be a timestamp