From 21f3c83a2ccc4470e5cd1ef27714fea544303b1b Mon Sep 17 00:00:00 2001 From: masasibata Date: Wed, 10 Dec 2025 21:14:08 +0300 Subject: [PATCH 1/3] refactor(models): rename to *Dto pattern and add ExternalSquads support - Rename HwidSettings to HwidSettingsDto - Rename CustomRemarks to CustomRemarksDto - Maintain backward compatibility via aliases - Update ExternalSquads models to use new DTO classes --- remnawave/models/__init__.py | 6 ++++++ remnawave/models/external_squads.py | 5 +++++ remnawave/models/subscriptions_settings.py | 17 +++++++++++------ 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/remnawave/models/__init__.py b/remnawave/models/__init__.py index c5a1c5d..9b9d900 100644 --- a/remnawave/models/__init__.py +++ b/remnawave/models/__init__.py @@ -207,6 +207,9 @@ from .subscriptions_settings import ( SubscriptionSettingsResponseDto, UpdateSubscriptionSettingsRequestDto, UpdateSubscriptionSettingsResponseDto, + CustomRemarksDto, + HwidSettingsDto, + # Backward compatibility aliases CustomRemarks, HwidSettings, ) @@ -492,6 +495,9 @@ __all__ = [ "GetSubscriptionSettingsResponseDto", "SubscriptionSettingsResponseDto", "UpdateSubscriptionSettingsRequestDto", + "CustomRemarksDto", + "HwidSettingsDto", + # Backward compatibility aliases "CustomRemarks", "HwidSettings", "UpdateSubscriptionSettingsResponseDto", diff --git a/remnawave/models/external_squads.py b/remnawave/models/external_squads.py index 634256e..ee579d3 100644 --- a/remnawave/models/external_squads.py +++ b/remnawave/models/external_squads.py @@ -4,6 +4,7 @@ from typing import Dict, List, Optional from uuid import UUID from pydantic import BaseModel, Field +from remnawave.models import CustomRemarksDto, HwidSettingsDto class TemplateType(StrEnum): @@ -54,6 +55,8 @@ class ExternalSquadDto(BaseModel): subscription_settings: Optional[ExternalSquadSubscriptionSettingsDto] = Field(None, alias="subscriptionSettings") host_overrides: Optional[ExternalSquadHostOverridesDto] = Field(None, alias="hostOverrides") response_headers: Optional[Dict[str, str]] = Field(None, alias="responseHeaders") + hwid_settings: Optional[HwidSettingsDto] = Field(None, alias="hwidSettings") + custom_remarks: Optional[CustomRemarksDto] = Field(None, alias="customRemarks") created_at: datetime = Field(alias="createdAt") updated_at: datetime = Field(alias="updatedAt") @@ -87,6 +90,8 @@ class UpdateExternalSquadRequestDto(BaseModel): templates: Optional[List[ExternalSquadTemplateDto]] = None subscription_settings: Optional[ExternalSquadSubscriptionSettingsDto] = Field(None, serialization_alias="subscriptionSettings") host_overrides: Optional[ExternalSquadHostOverridesDto] = Field(None, serialization_alias="hostOverrides") + hwid_settings: Optional[HwidSettingsDto] = Field(None, alias="hwidSettings") + custom_remarks: Optional[CustomRemarksDto] = Field(None, alias="customRemarks") response_headers: Optional[Dict[str, str]] = Field(None, serialization_alias="responseHeaders") diff --git a/remnawave/models/subscriptions_settings.py b/remnawave/models/subscriptions_settings.py index 41a69ae..94bc0c5 100644 --- a/remnawave/models/subscriptions_settings.py +++ b/remnawave/models/subscriptions_settings.py @@ -55,7 +55,7 @@ class ResponseRules(BaseModel): rules: List[ResponseRule] -class CustomRemarks(BaseModel): +class CustomRemarksDto(BaseModel): """Custom remarks for different user states""" expired_users: List[str] = Field(alias="expiredUsers", min_length=1) limited_users: List[str] = Field(alias="limitedUsers", min_length=1) @@ -64,7 +64,7 @@ class CustomRemarks(BaseModel): empty_internal_squads: List[str] = Field(alias="emptyInternalSquads", min_length=1) -class HwidSettings(BaseModel): +class HwidSettingsDto(BaseModel): """HWID (Hardware ID) settings""" enabled: bool fallback_device_limit: int = Field(alias="fallbackDeviceLimit") @@ -82,7 +82,7 @@ class SubscriptionSettingsResponseDto(BaseModel): serve_json_at_base_subscription: bool = Field(alias="serveJsonAtBaseSubscription") show_custom_remarks: bool = Field(alias="isShowCustomRemarks") - custom_remarks: CustomRemarks = Field(alias="customRemarks") + custom_remarks: CustomRemarksDto = Field(alias="customRemarks") happ_announce: Optional[str] = Field(None, alias="happAnnounce") happ_routing: Optional[str] = Field(None, alias="happRouting") @@ -90,7 +90,7 @@ class SubscriptionSettingsResponseDto(BaseModel): randomize_hosts: bool = Field(alias="randomizeHosts") response_rules: Optional[ResponseRules] = Field(None, alias="responseRules") - hwid_settings: Optional[HwidSettings] = Field(None, alias="hwidSettings") + hwid_settings: Optional[HwidSettingsDto] = Field(None, alias="hwidSettings") created_at: datetime = Field(alias="createdAt") updated_at: datetime = Field(alias="updatedAt") @@ -118,7 +118,7 @@ class UpdateSubscriptionSettingsRequestDto(BaseModel): ) is_show_custom_remarks: Optional[bool] = Field(None, serialization_alias="isShowCustomRemarks") - custom_remarks: Optional[CustomRemarks] = Field(None, serialization_alias="customRemarks") + custom_remarks: Optional[CustomRemarksDto] = Field(None, serialization_alias="customRemarks") happ_announce: Optional[Annotated[str, StringConstraints(max_length=200)]] = Field( None, serialization_alias="happAnnounce" @@ -130,4 +130,9 @@ class UpdateSubscriptionSettingsRequestDto(BaseModel): randomize_hosts: Optional[bool] = Field(None, serialization_alias="randomizeHosts") response_rules: Optional[ResponseRules] = Field(None, serialization_alias="responseRules") - hwid_settings: Optional[HwidSettings] = Field(None, serialization_alias="hwidSettings") \ No newline at end of file + hwid_settings: Optional[HwidSettingsDto] = Field(None, serialization_alias="hwidSettings") + + +# Backward compatibility aliases +CustomRemarks = CustomRemarksDto +HwidSettings = HwidSettingsDto \ No newline at end of file From 8979e2a588f0c9b146ef5f56572b9985811eeaa8 Mon Sep 17 00:00:00 2001 From: Artem Date: Thu, 11 Dec 2025 08:46:33 +0100 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=82=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=B2=D0=BE=D0=B7?= =?UTF-8?q?=D0=B2=D1=80=D0=B0=D1=89=D0=B0=D0=B5=D0=BC=D0=BE=D0=B3=D0=BE=20?= =?UTF-8?q?=D0=B7=D0=BD=D0=B0=D1=87=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B2=20?= =?UTF-8?q?=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8=20create=5Fhapp=5Fcr?= =?UTF-8?q?ypto=5Flink?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 2 +- remnawave/utils/happ_crypt.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 0a00229..96dd1c1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "remnawave" -version = "2.3.2" +version = "2.3.2rc1" description = "A Python SDK for interacting with the Remnawave API v2.3.2." authors = [ {name = "Artem",email = "dev@forestsnet.com"} diff --git a/remnawave/utils/happ_crypt.py b/remnawave/utils/happ_crypt.py index a70babc..937b1dc 100644 --- a/remnawave/utils/happ_crypt.py +++ b/remnawave/utils/happ_crypt.py @@ -52,6 +52,6 @@ def create_happ_crypto_link(content: str, method: Literal["v3", "v4"] = "v4") -> content.encode("utf-8"), padding.PKCS1v15() # RSA_PKCS1_PADDING ) - return "happ://crypt{" + method.lower().replace("v", "") + "/" + base64.b64encode(encrypted).decode() + return "happ://crypt" + method.lower().replace("v", "") + "/" + base64.b64encode(encrypted).decode() except Exception: return "" From e429a51c89746f7188be72553cde1568d9725f0b Mon Sep 17 00:00:00 2001 From: Artem Date: Thu, 11 Dec 2025 08:49:00 +0100 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5=D1=80=D0=B6?= =?UTF-8?q?=D0=BA=D1=83=20=D0=B2=D0=B5=D1=80=D1=81=D0=B8=D0=B9=20=D0=B2=20?= =?UTF-8?q?=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D0=B8=20Happ?= =?UTF-8?q?=20Crypto=20Link?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- remnawave/models/users.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/remnawave/models/users.py b/remnawave/models/users.py index 12c544b..2e7ba56 100644 --- a/remnawave/models/users.py +++ b/remnawave/models/users.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import Annotated, List, Optional +from typing import Annotated, List, Literal, Optional from uuid import UUID from pydantic import ( @@ -177,6 +177,13 @@ class UserResponseDto(BaseModel): """Generate Happ Crypto Link""" crypto_link = create_happ_crypto_link(self.subscription_url) return HappCrypto(cryptoLink=crypto_link) + + def happ_with_version(self, version: Literal["v3", "v4"] = "v4") -> HappCrypto: + return self._generate_happ(version=version) + + def _generate_happ(self, version): + crypto_link = create_happ_crypto_link(content=self.subscription_url, method=version) + return HappCrypto(cryptoLink=crypto_link) class RevokeUserRequestDto(BaseModel):