diff --git a/app/db/migrations/versions/b613375d2fca_add_new_protocols_to_proxytypes_enum.py b/app/db/migrations/versions/b613375d2fca_add_new_protocols_to_proxytypes_enum.py new file mode 100644 index 0000000..e03265a --- /dev/null +++ b/app/db/migrations/versions/b613375d2fca_add_new_protocols_to_proxytypes_enum.py @@ -0,0 +1,39 @@ +"""add new protocols to ProxyTypes enum + +Revision ID: b613375d2fca +Revises: 1992c49c5990 +Create Date: 2024-10-29 23:22:08.887104 + +""" + +from alembic import op + +# revision identifiers, used by Alembic. +revision = "b613375d2fca" +down_revision = "1992c49c5990" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + bind = op.get_bind() + dialect = bind.dialect.name + + if dialect == "postgresql": + op.execute("ALTER TYPE proxytypes ADD VALUE 'Shadowsocks2022'") + op.execute("ALTER TYPE proxytypes ADD VALUE 'WireGuard'") + op.execute("ALTER TYPE proxytypes ADD VALUE 'TUIC'") + elif dialect == "mysql": + op.execute( + "ALTER TABLE inbounds MODIFY protocol ENUM('VMess', 'VLESS', 'Trojan', 'Shadowsocks', 'Shadowsocks2022', 'Hysteria2', 'WireGuard', 'TUIC')" + ) + + +def downgrade() -> None: + bind = op.get_bind() + dialect = bind.dialect.name + + if dialect == "mysql": + op.execute( + "ALTER TABLE inbounds MODIFY protocol ENUM('VMess', 'VLESS', 'Shadowsocks', 'Trojan', 'Hysteria2')" + ) diff --git a/app/models/proxy.py b/app/models/proxy.py index 3385dbf..b1a64d7 100644 --- a/app/models/proxy.py +++ b/app/models/proxy.py @@ -11,7 +11,10 @@ class ProxyTypes(str, Enum): VLESS = "vless" Trojan = "trojan" Shadowsocks = "shadowsocks" + Shadowsocks2022 = "shadowsocks2022" Hysteria2 = "hysteria2" + WireGuard = "wireguard" + TUIC = "tuic" class InboundHostSecurity(str, Enum): diff --git a/app/routes/subscription.py b/app/routes/subscription.py index 572e47d..29510a8 100644 --- a/app/routes/subscription.py +++ b/app/routes/subscription.py @@ -140,6 +140,7 @@ def user_get_usage( client_type_mime_type = { "sing-box": "application/json", + "wireguard": "application/json", "clash-meta": "text/yaml", "clash": "text/yaml", "xray": "application/json", @@ -152,7 +153,9 @@ def user_subscription_with_client_type( db: DBDep, db_user: SubUserDep, request: Request, - client_type: str = Path(regex="sing-box|clash-meta|clash|xray|v2ray"), + client_type: str = Path( + regex="^(sing-box|clash-meta|clash|xray|v2ray|links|wireguard)$" + ), ): """ Subscription by client type; v2ray, xray, sing-box, clash and clash-meta formats supported diff --git a/app/utils/share.py b/app/utils/share.py index c29009f..fc4f5e6 100644 --- a/app/utils/share.py +++ b/app/utils/share.py @@ -16,6 +16,7 @@ from v2share import ( ClashConfig, ClashMetaConfig, XrayConfig, + WireGuardConfig, ) from v2share.base import BaseConfig from v2share.links import LinksConfig @@ -49,10 +50,12 @@ subscription_handlers: dict[str, Type[BaseConfig]] = { "clash-meta": ClashMetaConfig, "clash": ClashConfig, "sing-box": SingBoxConfig, + "wireguard": WireGuardConfig, } handlers_templates = { LinksConfig: None, + WireGuardConfig: None, XrayConfig: XRAY_SUBSCRIPTION_TEMPLATE or resources.files("app.templates") / "xray.json", ClashConfig: CLASH_SUBSCRIPTION_TEMPLATE, @@ -151,6 +154,21 @@ def format_time_left(seconds_left: int) -> str: return " ".join(result) +def calculate_client_address(interface_address: str, user_id: int) -> str: + try: + interface = ipaddress.ip_interface(interface_address) + address = interface.ip + network = interface.network + except ValueError: + return "" + user_address = network[user_id] + if user_address == network[0]: + user_address = network.broadcast_address - 1 + if user_address == address: + user_address = network.broadcast_address - 2 + return user_address.compressed + "/" + str(user_address.max_prefixlen) + + def setup_format_variables(extra_data: dict) -> dict: expire_strategy = extra_data.get("expire_strategy") expire_datetime = extra_data.get("expire_date") @@ -277,13 +295,8 @@ def generate_user_configs( fingerprint=host.fingerprint.value or inbound.get("fp"), reality_pbk=inbound.get("pbk"), reality_sid=inbound.get("sid"), - client_address=( - ipaddress.ip_network(inbound["address"], strict=False)[ - user_id - ].compressed - + "/32" - if inbound.get("address") - else None + client_address=calculate_client_address( + inbound.get("address"), user_id ), flow=inbound.get("flow"), allow_insecure=host.allowinsecure, diff --git a/requirements.txt b/requirements.txt index 5f3c7d7..9f02543 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,7 +23,7 @@ aiohttp==3.10.2 xxhash==3.4.1 grpcio==1.65.4 psycopg==3.1.18 -v2share==0.1.0b21 +v2share==0.1.0b22 PyJWT~=2.8.0 PyNaCl==1.5.0 starlette==0.40.0