fix + vershions configs
This commit is contained in:
parent
9987500ac0
commit
89651a8e81
5 changed files with 94 additions and 71 deletions
|
|
@ -9,6 +9,6 @@ class Config(Base):
|
||||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), nullable=False)
|
user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), nullable=False)
|
||||||
name: Mapped[str] = mapped_column(String(64), nullable=False)
|
name: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||||
config: Mapped[str] = mapped_column(String(1024), nullable=False, unique=True)
|
config: Mapped[str] = mapped_column(String(1024), nullable=False)
|
||||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||||
deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ from .server import Server
|
||||||
class User(Base):
|
class User(Base):
|
||||||
__tablename__ = "users"
|
__tablename__ = "users"
|
||||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||||
email: Mapped[str] = mapped_column(String(256), index=True, nullable=False, unique=True)
|
email: Mapped[str] = mapped_column(String(256), index=True, nullable=False)
|
||||||
pass_hash: Mapped[str] = mapped_column(String(512), nullable=False)
|
pass_hash: Mapped[str] = mapped_column(String(512), nullable=False)
|
||||||
server_id: Mapped[int] = mapped_column(ForeignKey("servers.id"))
|
server_id: Mapped[int] = mapped_column(ForeignKey("servers.id"))
|
||||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,10 @@ async def signup(body: UserCreate, db: AsyncSession = Depends(get_db)):
|
||||||
detail="Promo-code is not valid"
|
detail="Promo-code is not valid"
|
||||||
)
|
)
|
||||||
existing = await db.execute(
|
existing = await db.execute(
|
||||||
select(User).where(User.email == body.email)
|
select(User).where(
|
||||||
|
User.email == body.email,
|
||||||
|
User.deleted_at.is_(None)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
if existing.scalar_one_or_none():
|
if existing.scalar_one_or_none():
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
|
|
||||||
155
API/utils/xui.py
155
API/utils/xui.py
|
|
@ -5,6 +5,84 @@ from urllib.parse import quote
|
||||||
from httpx import AsyncClient
|
from httpx import AsyncClient
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
|
|
||||||
|
class Configs:
|
||||||
|
def __init__(self, inbound_id: int, host: str, client_email: str, display_name: str):
|
||||||
|
self.inbound_id = inbound_id
|
||||||
|
self.host = host
|
||||||
|
self.client_email = client_email
|
||||||
|
self.display_name = display_name
|
||||||
|
|
||||||
|
async def legacy_payload(self, data: dict,) -> dict:
|
||||||
|
inbounds = data.get("obj")
|
||||||
|
inbound = next((i for i in inbounds if i.get("id") == self.inbound_id), None)
|
||||||
|
if not inbound:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=404,
|
||||||
|
detail=f"Server not found"
|
||||||
|
)
|
||||||
|
stream_settings = json.loads(inbound.get("streamSettings"))
|
||||||
|
reality = stream_settings.get("realitySettings")
|
||||||
|
short_ids = reality.get("shortIds")
|
||||||
|
suid = random.choice(short_ids)
|
||||||
|
client_uuid = str(uuid.uuid4())
|
||||||
|
return {
|
||||||
|
"id": self.inbound_id,
|
||||||
|
"settings": json.dumps({
|
||||||
|
"clients": [{
|
||||||
|
"id": client_uuid,
|
||||||
|
"flow": "xtls-rprx-vision",
|
||||||
|
"email": self.client_email,
|
||||||
|
"limitIp": 0,
|
||||||
|
"totalGB": 0,
|
||||||
|
"expiryTime": 0,
|
||||||
|
"enable": True,
|
||||||
|
"tgId": "",
|
||||||
|
"subId": suid,
|
||||||
|
"comment": "",
|
||||||
|
"reset": 0
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async def legacy_config(self, data: dict) -> str:
|
||||||
|
inbounds = data.get("obj")
|
||||||
|
inbound = next((i for i in inbounds if i.get("id") == self.inbound_id), None)
|
||||||
|
if not inbound:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=500,
|
||||||
|
detail="Server error"
|
||||||
|
)
|
||||||
|
settings = json.loads(inbound.get("settings"))
|
||||||
|
clients = settings.get("clients")
|
||||||
|
current_client = next((i for i in clients if i.get("email") == self.client_email), None)
|
||||||
|
if not current_client:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=500,
|
||||||
|
detail="Server error"
|
||||||
|
)
|
||||||
|
client_uuid = current_client.get("id")
|
||||||
|
sub_id = current_client.get("subId")
|
||||||
|
stream_settings = json.loads(inbound.get("streamSettings"))
|
||||||
|
reality = stream_settings.get("realitySettings")
|
||||||
|
server_names = reality.get("serverNames")
|
||||||
|
setting = reality.get("settings")
|
||||||
|
pbk = setting.get("publicKey")
|
||||||
|
fp = setting.get("fingerprint")
|
||||||
|
spx = quote(setting.get("spiderX"), safe='')
|
||||||
|
sni = random.choice(server_names)
|
||||||
|
port = inbound.get("port")
|
||||||
|
return (
|
||||||
|
f"vless://{client_uuid}@{self.host}:{port}?"
|
||||||
|
f"security=reality&"
|
||||||
|
f"pbk={pbk}&"
|
||||||
|
f"fp={fp}&"
|
||||||
|
f"sni={sni}&"
|
||||||
|
f"sid={sub_id}&"
|
||||||
|
f"spx={spx}&"
|
||||||
|
f"flow=xtls-rprx-vision#"
|
||||||
|
f"{self.display_name}"
|
||||||
|
)
|
||||||
|
|
||||||
class XUIClient:
|
class XUIClient:
|
||||||
def __init__(self, host: str, base_url: str, username: str, password: str, inbound_id: int, version: str):
|
def __init__(self, host: str, base_url: str, username: str, password: str, inbound_id: int, version: str):
|
||||||
self.host = host
|
self.host = host
|
||||||
|
|
@ -39,86 +117,27 @@ class XUIClient:
|
||||||
)
|
)
|
||||||
|
|
||||||
async def add_client(self, client_email: str, display_name: str) -> str:
|
async def add_client(self, client_email: str, display_name: str) -> str:
|
||||||
|
configs = Configs(self.inbound_id, self.host, client_email, display_name)
|
||||||
await self._login()
|
await self._login()
|
||||||
resp = await self.session.post(f"{self.base_url}/panel/inbound/list")
|
resp = await self.session.post(f"{self.base_url}/panel/inbound/list")
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
data = resp.json()
|
if self.version == "legacy":
|
||||||
inbounds = data.get("obj")
|
resp = await self.session.post(f"{self.base_url}/panel/inbound/addClient", json=configs.legacy_payload(resp.json()))
|
||||||
inbound = next((i for i in inbounds if i.get("id") == self.inbound_id), None)
|
else:
|
||||||
if not inbound:
|
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=404,
|
status_code=500,
|
||||||
detail=f"Server not found"
|
detail="Server error"
|
||||||
)
|
)
|
||||||
stream_settings = json.loads(inbound.get("streamSettings"))
|
|
||||||
reality = stream_settings.get("realitySettings")
|
|
||||||
short_ids = reality.get("shortIds")
|
|
||||||
server_names = reality.get("serverNames")
|
|
||||||
suid = random.choice(short_ids)
|
|
||||||
sni = random.choice(server_names)
|
|
||||||
pbk = reality.get("settings").get("publicKey")
|
|
||||||
client_uuid = str(uuid.uuid4())
|
|
||||||
add_payload = {
|
|
||||||
"id": self.inbound_id,
|
|
||||||
"settings": json.dumps({
|
|
||||||
"clients": [{
|
|
||||||
"id": client_uuid,
|
|
||||||
"flow": "xtls-rprx-vision",
|
|
||||||
"email": client_email,
|
|
||||||
"limitIp": 0,
|
|
||||||
"totalGB": 0,
|
|
||||||
"expiryTime": 0,
|
|
||||||
"enable": True,
|
|
||||||
"tgId": "",
|
|
||||||
"subId": suid,
|
|
||||||
"comment": "",
|
|
||||||
"reset": 0
|
|
||||||
}]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
resp = await self.session.post(f"{self.base_url}/panel/inbound/addClient", json=add_payload)
|
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
resp = await self.session.post(f"{self.base_url}/panel/inbound/list")
|
resp = await self.session.post(f"{self.base_url}/panel/inbound/list")
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
data = resp.json()
|
if self.version == "legacy":
|
||||||
inbounds = data.get("obj")
|
return configs.legacy_config(resp.json())
|
||||||
inbound = next((i for i in inbounds if i.get("id") == self.inbound_id), None)
|
else:
|
||||||
if not inbound:
|
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=500,
|
status_code=500,
|
||||||
detail="Server error"
|
detail="Server error"
|
||||||
)
|
)
|
||||||
settings = json.loads(inbound.get("settings"))
|
|
||||||
clients = settings.get("clients")
|
|
||||||
current_client = next((i for i in clients if i.get("email") == client_email), None)
|
|
||||||
if not current_client:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=500,
|
|
||||||
detail="Server error"
|
|
||||||
)
|
|
||||||
client_uuid = current_client.get("id")
|
|
||||||
sub_id = current_client.get("subId")
|
|
||||||
stream_settings = json.loads(inbound.get("streamSettings"))
|
|
||||||
reality = stream_settings.get("realitySettings")
|
|
||||||
server_names = reality.get("serverNames")
|
|
||||||
setting = reality.get("settings")
|
|
||||||
pbk = setting.get("publicKey")
|
|
||||||
fp = setting.get("fingerprint")
|
|
||||||
spx = quote(setting.get("spiderX"), safe='')
|
|
||||||
sni = random.choice(server_names)
|
|
||||||
port = inbound.get("port")
|
|
||||||
config_url = (
|
|
||||||
f"vless://{client_uuid}@{self.host}:{port}?"
|
|
||||||
f"security=reality&"
|
|
||||||
f"pbk={pbk}&"
|
|
||||||
f"fp={fp}&"
|
|
||||||
f"sni={sni}&"
|
|
||||||
f"sid={sub_id}&"
|
|
||||||
f"spx={spx}&"
|
|
||||||
f"flow=xtls-rprx-vision#"
|
|
||||||
f"{display_name}"
|
|
||||||
)
|
|
||||||
return config_url
|
|
||||||
|
|
||||||
async def get_client_traffic(self, client_email: str) -> int:
|
async def get_client_traffic(self, client_email: str) -> int:
|
||||||
await self._login()
|
await self._login()
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ services:
|
||||||
retries: 10
|
retries: 10
|
||||||
volumes:
|
volumes:
|
||||||
- db-data:/var/lib/postgresql
|
- db-data:/var/lib/postgresql
|
||||||
|
#TODO Удалить проброс портов
|
||||||
ports:
|
ports:
|
||||||
- 5432:5432
|
- 5432:5432
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue