Files
archived-MoviePilot-Plugins/plugins.v2/clashruleprovider/models/proxy/shadowsocksproxy.py

111 lines
4.0 KiB
Python

from typing import Optional, Dict, Literal, List, Union
from pydantic import Field, BaseModel, field_validator, ValidationInfo
from .proxybase import ProxyBase
ShadowsocksCipherType = Literal[
# AES 相关
'aes-128-ctr', 'aes-192-ctr', 'aes-256-ctr',
'aes-128-cfb', 'aes-192-cfb', 'aes-256-cfb',
'aes-128-gcm', 'aes-192-gcm', 'aes-256-gcm',
'aes-128-com', 'aes-192-com', 'aes-256-com',
'aes-128-gcm-siv', 'aes-256-gcm-siv',
# CHACHA 相关
'chacha20-ietf', 'chacha20', 'xchacha20',
'chacha20-ietf-poly1305', 'xchacha20-ietf-poly1305',
'chacha8-ietf-poly1305', 'xchacha8-ietf-poly1305',
# 2022 Blake3 相关
'2022-blake3-aes-128-gcm', '2022-blake3-aes-256-gcm', '2022-blake3-chacha20-poly1305',
# LEA 相关
'lea-128-gcm', 'lea-192-gcm', 'lea-256-gcm',
# 其他
'rabbit128-poly1305', 'aegis-128l', 'aegis-256', 'aez-384', 'deoxys-ii-256-128', 'rc4-md5', 'none'
]
class ObfsPluginOpts(BaseModel):
mode: Literal['tls', 'http']
host: Optional[str] = Field(default="bing.com")
class V2rayPluginOpts(BaseModel):
mode: Literal['websocket'] = 'websocket'
host: Optional[str] = Field(default="bing.com")
path: Optional[str] = None
tls: Optional[bool] = False
fingerprint: Optional[str] = None
headers: Optional[Dict[str, str]] = None
skip_cert_verify: Optional[bool] = Field(False, alias='skip-cert-verify')
mux: Optional[bool] = True
v2ray_http_upgrade: Optional[bool] = Field(False, alias='v2ray-http-upgrade')
v2ray_http_upgrade_fast_open: Optional[bool] = Field(False, alias='v2ray-http-upgrade-fast-open')
class GostPluginOpts(BaseModel):
mode: Literal['websocket'] = 'websocket'
host: Optional[str] = Field(default="bing.com")
path: Optional[str] = None
tls: Optional[bool] = False
fingerprint: Optional[str] = None
headers: Optional[Dict[str, str]] = None
skip_cert_verify: Optional[bool] = Field(False, alias='skip-cert-verify')
mux: Optional[bool] = True
class ShadowTlsPluginOpts(BaseModel):
password: Optional[str] = None
host: str
fingerprint: Optional[str] = None
skip_cert_verify: Optional[bool] = Field(False, alias='skip-cert-verify')
version: Optional[Literal[1, 2, 3]] = 2
alpn: Optional[List[str]] = None
class RestlsPluginOpts(BaseModel):
password: str
host: str
version_hint: str = Field(alias='version-hint')
restls_script: Optional[str] = Field(None, alias='restls-script')
class ShadowsocksProxy(ProxyBase):
type: Literal['ss'] = 'ss'
cipher: ShadowsocksCipherType
password: str
udp_over_tcp: Optional[bool] = Field(None, alias='udp-over-tcp')
udp_over_tcp_version: Optional[Literal[1, 2]] = Field(1, alias='udp-over-tcp-version')
client_fingerprint: Optional[Literal['chrome', 'ios', 'firefox', 'safari']] = Field(None,
alias='client-fingerprint')
plugin: Optional[Literal['obfs', 'v2ray-plugin', 'shadow-tls', 'restls', 'gost-plugin']] = None
plugin_opts: Optional[Union[
ObfsPluginOpts,
V2rayPluginOpts,
GostPluginOpts,
ShadowTlsPluginOpts,
RestlsPluginOpts,
]] = Field(None, alias='plugin-opts')
@field_validator("plugin_opts")
@classmethod
def validate_plugin_opts(cls, v, info: ValidationInfo):
plugin = info.data.get("plugin")
if plugin and v:
if not isinstance(plugin, str):
raise ValueError("plugin must be a string")
plugin_model_map = {
"obfs": "ObfsPluginOpts",
"v2ray-plugin": "V2rayPluginOpts",
"gost-plugin": "GostPluginOpts",
"shadow-tls": "ShadowTlsPluginOpts",
"restls": "RestlsPluginOpts",
}
expected_model = plugin_model_map.get(plugin)
if expected_model and v.__class__.__name__ != expected_model:
raise ValueError(f"{plugin} plugin requires {expected_model}")
return v