gitscope
← marzneshin / Diff · eb74041 → eb74041
Changes eb74041..eb74041
Patch commit
diff --git a/app/db/crud.py b/app/db/crud.py
index a666eee..a406a62 100644
--- a/app/db/crud.py
+++ b/app/db/crud.py
@@ -217,15 +217,9 @@ def get_users(db: Session,
def get_user_usages(db: Session, dbuser: User, start: datetime, end: datetime,
) -> List[UserUsageResponse]:
- usages = {}
+ usages = dict()
- usages[0] = UserUsageResponse( # Main Core
- node_id=None,
- node_name="Master",
- used_traffic=0
- )
for node in db.query(Node).all():
-
usages[node.id] = UserUsageResponse(
node_id=node.id,
node_name=node.name,
@@ -363,13 +357,6 @@ def reset_user_data_usage(db: Session, dbuser: User):
def revoke_user_sub(db: Session, dbuser: User):
- dbuser.sub_revoked_at = datetime.utcnow()
-
- # user = UserResponse.model_validate(dbuser)
- # for proxy_type, settings in user.proxies.copy().items():
- # settings.revoke()
- # user.proxies[proxy_type] = settings
- # dbuser = update_user(db, dbuser, user)
dbuser.key = secrets.token_hex(16)
db.commit()
db.refresh(dbuser)
diff --git a/app/db/migrations/versions/20faa9f18c0a_init.py b/app/db/migrations/versions/20faa9f18c0a_init.py
index 0e2a38c..adefe4b 100644
--- a/app/db/migrations/versions/20faa9f18c0a_init.py
+++ b/app/db/migrations/versions/20faa9f18c0a_init.py
@@ -115,7 +115,6 @@ def upgrade() -> None:
sa.Column('settings', sa.String(), nullable=True),
sa.Column('expire', sa.Integer(), nullable=True),
sa.Column('admin_id', sa.Integer(), nullable=True),
- sa.Column('sub_revoked_at', sa.DateTime(), nullable=True),
sa.Column('sub_updated_at', sa.DateTime(), nullable=True),
sa.Column('sub_last_user_agent', sa.String(length=512), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=True),
diff --git a/app/db/models.py b/app/db/models.py
index 02fcd1e..f2a9eea 100644
--- a/app/db/models.py
+++ b/app/db/models.py
@@ -83,7 +83,6 @@ class User(Base):
expire = Column(Integer, nullable=True)
admin_id = Column(Integer, ForeignKey("admins.id"))
admin = relationship("Admin", back_populates="users")
- sub_revoked_at = Column(DateTime, nullable=True, default=None)
sub_updated_at = Column(DateTime, nullable=True, default=None)
sub_last_user_agent = Column(String(512), nullable=True, default=None)
created_at = Column(DateTime, default=datetime.utcnow)
diff --git a/app/models/user.py b/app/models/user.py
index fb67664..76ea2df 100644
--- a/app/models/user.py
+++ b/app/models/user.py
@@ -7,7 +7,6 @@ from typing import List, Optional, Union
from pydantic import field_validator, ConfigDict, BaseModel, Field, validator, computed_field, ValidationInfo
from app.models.proxy import InboundBase
-from app.utils.jwt import create_subscription_token
from config import XRAY_SUBSCRIPTION_PATH, XRAY_SUBSCRIPTION_URL_PREFIX
USERNAME_REGEXP = re.compile(r"^(?=\w{3,32}\b)[a-zA-Z0-9-_@.]+(?:_[a-zA-Z0-9-_@.]+)*$")
@@ -203,8 +202,7 @@ class UserResponse(User):
def subscription_url(self) -> str:
salt = secrets.token_hex(8)
url_prefix = (XRAY_SUBSCRIPTION_URL_PREFIX).replace('*', salt)
- token = create_subscription_token(self.username)
- return f"{url_prefix}/{XRAY_SUBSCRIPTION_PATH}/{token}"
+ return f"{url_prefix}/{XRAY_SUBSCRIPTION_PATH}/{self.username}/{self.key}"
class UsersResponse(BaseModel):
diff --git a/app/utils/jwt.py b/app/utils/jwt.py
index 0edc273..aca1ad2 100644
--- a/app/utils/jwt.py
+++ b/app/utils/jwt.py
@@ -38,20 +38,3 @@ def get_admin_payload(token: str) -> Union[dict, None]:
return {"username": username, "is_sudo": access == "sudo", "created_at": created_at}
except JWTError:
return
-
-
-def create_subscription_token(username: str) -> str:
- data = {"sub": username, "access": "subscription", "iat": datetime.utcnow()+timedelta(seconds=1)}
- encoded_jwt = jwt.encode(data, get_secret_key(), algorithm="HS256")
- return encoded_jwt
-
-
-def get_subscription_payload(token: str) -> Union[dict, None]:
- try:
- payload = jwt.decode(token, get_secret_key(), algorithms=["HS256"])
- if payload.get("access") != "subscription":
- return
-
- return {"username": payload['sub'], "created_at": datetime.utcfromtimestamp(payload['iat'])}
- except JWTError:
- return
diff --git a/app/utils/notification.py b/app/utils/notification.py
index 327e2ea..da20e6b 100644
--- a/app/utils/notification.py
+++ b/app/utils/notification.py
@@ -1,7 +1,6 @@
from collections import deque
from datetime import datetime as dt
from enum import Enum
-from typing import Type
from pydantic import BaseModel
diff --git a/app/views/subscription.py b/app/views/subscription.py
index ccb416e..6b1d5b4 100644
--- a/app/views/subscription.py
+++ b/app/views/subscription.py
@@ -8,7 +8,6 @@ from app import app
from app.db import Session, crud, get_db
from app.models.user import UserResponse
from app.templates import render_template
-from app.utils.jwt import get_subscription_payload
from app.utils.share import encode_title, generate_subscription
from config import (
SUB_PROFILE_TITLE,
@@ -19,9 +18,10 @@ from config import (
)
-@app.get("/%s/{token}/" % XRAY_SUBSCRIPTION_PATH, tags=['Subscription'])
-@app.get("/%s/{token}" % XRAY_SUBSCRIPTION_PATH, include_in_schema=False)
-def user_subscription(token: str,
+@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,
request: Request,
db: Session = Depends(get_db),
user_agent: str = Header(default="")):
@@ -37,17 +37,14 @@ def user_subscription(token: str,
"total": user.data_limit,
"expire": user.expire,
}
+ try:
+ int(key, 16)
+ except ValueError:
+ return Response(status_code=404)
- sub = get_subscription_payload(token)
- if not sub:
- return Response(status_code=204)
-
- dbuser = crud.get_user(db, sub['username'])
- if not dbuser or dbuser.created_at > sub['created_at']:
- return Response(status_code=204)
-
- if dbuser.sub_revoked_at and dbuser.sub_revoked_at > sub['created_at']:
- return Response(status_code=204)
+ dbuser = crud.get_user(db, username)
+ if not dbuser or dbuser.key != key:
+ return Response(status_code=404)
user: UserResponse = UserResponse.model_validate(dbuser)
@@ -95,39 +92,37 @@ def user_subscription(token: str,
return Response(content=conf, media_type="text/plain", headers=response_headers)
-@app.get("/%s/{token}/info" % XRAY_SUBSCRIPTION_PATH, tags=['Subscription'], response_model=UserResponse)
-def user_subscription_info(token: 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)):
- sub = get_subscription_payload(token)
- if not sub:
- return Response(status_code=404)
-
- dbuser = crud.get_user(db, sub['username'])
- if not dbuser or dbuser.created_at > sub['created_at']:
+ try:
+ int(key, 16)
+ except ValueError:
return Response(status_code=404)
- elif dbuser.sub_revoked_at and dbuser.sub_revoked_at > sub['created_at']:
+ dbuser = crud.get_user(db, username)
+ if not dbuser or key != dbuser.key:
return Response(status_code=404)
return dbuser
-@app.get("/%s/{token}/usage" % XRAY_SUBSCRIPTION_PATH, tags=['Subscription'])
-def user_get_usage(token: str,
+@app.get("/%s/{username}/{key}/usage" % XRAY_SUBSCRIPTION_PATH, tags=['Subscription'])
+def user_get_usage(username: str,
+ key: str,
start: str = None,
end: str = None,
db: Session = Depends(get_db)):
- sub = get_subscription_payload(token)
- if not sub:
- return Response(status_code=204)
-
- dbuser = crud.get_user(db, sub['username'])
- if not dbuser or dbuser.created_at > sub['created_at']:
- return Response(status_code=204)
+ try:
+ int(key, 16)
+ except ValueError:
+ return Response(status_code=404)
- if dbuser.sub_revoked_at and dbuser.sub_revoked_at > sub['created_at']:
- return Response(status_code=204)
+ dbuser = crud.get_user(db, username)
+ if not dbuser or key != dbuser.key:
+ return Response(status_code=404)
if start is None:
start_date = datetime.fromtimestamp(datetime.utcnow().timestamp() - 30 * 24 * 3600)
@@ -144,12 +139,13 @@ def user_get_usage(token: str,
return {"usages": usages, "username": dbuser.username}
-@app.get("/%s/{token}/{client_type}" % XRAY_SUBSCRIPTION_PATH, tags=['Subscription'])
+@app.get("/%s/{username}/{key}/{client_type}" % XRAY_SUBSCRIPTION_PATH, tags=['Subscription'])
def user_subscription_with_client_type(
- token: str,
- request: Request,
- client_type: str = Path(..., regex="sing-box|clash-meta|clash|outline|v2ray"),
- db: Session = Depends(get_db),
+ username: str,
+ key: str,
+ request: Request,
+ client_type: str = Path(..., regex="sing-box|clash-meta|clash|outline|v2ray"),
+ db: Session = Depends(get_db),
):
"""
Subscription link, v2ray, clash, sing-box, outline and clash-meta supported
@@ -163,16 +159,14 @@ def user_subscription_with_client_type(
"expire": user.expire,
}
- sub = get_subscription_payload(token)
- if not sub:
- return Response(status_code=204)
-
- dbuser = crud.get_user(db, sub['username'])
- if not dbuser or dbuser.created_at > sub['created_at']:
- return Response(status_code=204)
+ try:
+ int(key, 16)
+ except ValueError:
+ return Response(status_code=404)
- if dbuser.sub_revoked_at and dbuser.sub_revoked_at > sub['created_at']:
- return Response(status_code=204)
+ dbuser = crud.get_user(db, username)
+ if not dbuser or key != dbuser.key:
+ return Response(status_code=404)
user: UserResponse = UserResponse.model_validate(dbuser)