diff --git a/app/dashboard/build/locales/en.json b/app/dashboard/build/locales/en.json index 09f49343..a81f47b5 100644 --- a/app/dashboard/build/locales/en.json +++ b/app/dashboard/build/locales/en.json @@ -105,6 +105,7 @@ "hostsDialog.host.wildcard": "Use * to generate a random string (works for wildcard domain names)", "hostsDialog.sockopt": "Sockopt", "hostsDialog.muxEnable": "Enable MUX", + "hostsDialog.randomUserAgent":"Use random user agent", "hostsDialog.allowinsecure": "Allow Insecure", "hostsDialog.fragment": "Fragment pattern", "hostsDialog.fragment.info": "Correct pattern: length,interval,packets", diff --git a/app/dashboard/build/locales/fa.json b/app/dashboard/build/locales/fa.json index 57e79ace..0b0fbd88 100644 --- a/app/dashboard/build/locales/fa.json +++ b/app/dashboard/build/locales/fa.json @@ -106,6 +106,7 @@ "hostsDialog.host.wildcard": "از * برای ساخت عبارت تصادفی استفاده کنید (برای نام‌های wildcard کار می‌کند)", "hostsDialog.sockopt": "Sockopt", "hostsDialog.muxEnable": "فعالسازی MUX", + "hostsDialog.randomUserAgent":"استفاده از User Agent تصادفی", "hostsDialog.allowinsecure": "Allow Insecure", "hostsDialog.fragment": "الگو فرگمنت", "hostsDialog.fragment.info": "length,interval,packet (e.g. 10-100,100-200,tlshello)", diff --git a/app/dashboard/build/locales/ru.json b/app/dashboard/build/locales/ru.json index 7d3409aa..6e52cec1 100644 --- a/app/dashboard/build/locales/ru.json +++ b/app/dashboard/build/locales/ru.json @@ -103,6 +103,7 @@ "hostsDialog.host.wildcard": "Используйте *, чтобы сгенерировать случайную строку (работает для wildcard доменов)", "hostsDialog.sockopt": "Sockopt", "hostsDialog.muxEnable": "Давать возможность MUX", + "hostsDialog.randomUserAgent":"Use random user agent", "hostsDialog.allowinsecure": "Allow Insecure", "hostsDialog.fragment": "Шаблон фрагмента", "hostsDialog.fragment.info": "length,interval,packet (e.g. 10-100,100-200,tlshello)", diff --git a/app/dashboard/build/locales/zh.json b/app/dashboard/build/locales/zh.json index f9817e28..65789ad4 100644 --- a/app/dashboard/build/locales/zh.json +++ b/app/dashboard/build/locales/zh.json @@ -97,6 +97,7 @@ "hostsDialog.fingerprint": "指纹", "hostsDialog.sockopt": "Sockopt", "hostsDialog.muxEnable": "使能够 MUX", + "hostsDialog.randomUserAgent":"Use random user agent", "hostsDialog.allowinsecure": "Allow Insecure", "hostsDialog.fragment": "碎片图案", "hostsDialog.fragment.info": "length,interval,packet (e.g. 10-100,100-200,tlshello)", diff --git a/app/dashboard/public/locales/en.json b/app/dashboard/public/locales/en.json index 09f49343..a81f47b5 100644 --- a/app/dashboard/public/locales/en.json +++ b/app/dashboard/public/locales/en.json @@ -105,6 +105,7 @@ "hostsDialog.host.wildcard": "Use * to generate a random string (works for wildcard domain names)", "hostsDialog.sockopt": "Sockopt", "hostsDialog.muxEnable": "Enable MUX", + "hostsDialog.randomUserAgent":"Use random user agent", "hostsDialog.allowinsecure": "Allow Insecure", "hostsDialog.fragment": "Fragment pattern", "hostsDialog.fragment.info": "Correct pattern: length,interval,packets", diff --git a/app/dashboard/public/locales/fa.json b/app/dashboard/public/locales/fa.json index 57e79ace..0b0fbd88 100644 --- a/app/dashboard/public/locales/fa.json +++ b/app/dashboard/public/locales/fa.json @@ -106,6 +106,7 @@ "hostsDialog.host.wildcard": "از * برای ساخت عبارت تصادفی استفاده کنید (برای نام‌های wildcard کار می‌کند)", "hostsDialog.sockopt": "Sockopt", "hostsDialog.muxEnable": "فعالسازی MUX", + "hostsDialog.randomUserAgent":"استفاده از User Agent تصادفی", "hostsDialog.allowinsecure": "Allow Insecure", "hostsDialog.fragment": "الگو فرگمنت", "hostsDialog.fragment.info": "length,interval,packet (e.g. 10-100,100-200,tlshello)", diff --git a/app/dashboard/public/locales/ru.json b/app/dashboard/public/locales/ru.json index 7d3409aa..6e52cec1 100644 --- a/app/dashboard/public/locales/ru.json +++ b/app/dashboard/public/locales/ru.json @@ -103,6 +103,7 @@ "hostsDialog.host.wildcard": "Используйте *, чтобы сгенерировать случайную строку (работает для wildcard доменов)", "hostsDialog.sockopt": "Sockopt", "hostsDialog.muxEnable": "Давать возможность MUX", + "hostsDialog.randomUserAgent":"Use random user agent", "hostsDialog.allowinsecure": "Allow Insecure", "hostsDialog.fragment": "Шаблон фрагмента", "hostsDialog.fragment.info": "length,interval,packet (e.g. 10-100,100-200,tlshello)", diff --git a/app/dashboard/public/locales/zh.json b/app/dashboard/public/locales/zh.json index f9817e28..65789ad4 100644 --- a/app/dashboard/public/locales/zh.json +++ b/app/dashboard/public/locales/zh.json @@ -97,6 +97,7 @@ "hostsDialog.fingerprint": "指纹", "hostsDialog.sockopt": "Sockopt", "hostsDialog.muxEnable": "使能够 MUX", + "hostsDialog.randomUserAgent":"Use random user agent", "hostsDialog.allowinsecure": "Allow Insecure", "hostsDialog.fragment": "碎片图案", "hostsDialog.fragment.info": "length,interval,packet (e.g. 10-100,100-200,tlshello)", diff --git a/app/dashboard/src/components/HostsDialog.tsx b/app/dashboard/src/components/HostsDialog.tsx index 9eb8efad..89d79d05 100644 --- a/app/dashboard/src/components/HostsDialog.tsx +++ b/app/dashboard/src/components/HostsDialog.tsx @@ -119,6 +119,7 @@ const hostsSchema = z.record( allowinsecure: z.boolean().nullable().default(false), is_disabled: z.boolean().default(true), fragment_setting: z.string().nullable(), + random_user_agent: z.boolean().default(false), security: z.string(), alpn: z.string(), fingerprint: z.string(), @@ -175,6 +176,7 @@ const AccordionInbound: FC = ({ allowinsecure: false, is_disabled: false, fragment_setting: "", + random_user_agent: false, security: "inbound_default", alpn: "", fingerprint: "", @@ -920,6 +922,28 @@ const AccordionInbound: FC = ({ )} + + + {t("hostsDialog.randomUserAgent")} + + {accordionErrors && + accordionErrors[index]?.random_user_agent && ( + + {accordionErrors[index]?.random_user_agent?.message} + + )} + diff --git a/app/db/crud.py b/app/db/crud.py index cb2edb1d..1affebb4 100644 --- a/app/db/crud.py +++ b/app/db/crud.py @@ -85,6 +85,7 @@ def update_hosts(db: Session, inbound_tag: str, modified_hosts: List[ProxyHostMo is_disabled=host.is_disabled, mux_enable=host.mux_enable, fragment_setting=host.fragment_setting, + random_user_agent=host.random_user_agent, ) for host in modified_hosts ] db.commit() diff --git a/app/db/migrations/versions/31f92220c0d0_add_support_random_user_agent.py b/app/db/migrations/versions/31f92220c0d0_add_support_random_user_agent.py new file mode 100644 index 00000000..65c9b341 --- /dev/null +++ b/app/db/migrations/versions/31f92220c0d0_add_support_random_user_agent.py @@ -0,0 +1,28 @@ +"""Add Support Random User-Agent + +Revision ID: 31f92220c0d0 +Revises: 4f045f53bef8 +Create Date: 2024-06-01 21:28:33.310627 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '31f92220c0d0' +down_revision = '4f045f53bef8' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('hosts', sa.Column('random_user_agent', sa.Boolean(), server_default='0', nullable=False)) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('hosts', 'random_user_agent') + # ### end Alembic commands ### diff --git a/app/db/models.py b/app/db/models.py index 65d94bf9..d19d90f6 100644 --- a/app/db/models.py +++ b/app/db/models.py @@ -194,6 +194,7 @@ class ProxyHost(Base): is_disabled = Column(Boolean, nullable=True, default=False) mux_enable = Column(Boolean, nullable=False, default=False, server_default='0') fragment_setting = Column(String(100), nullable=True) + random_user_agent = Column(Boolean, nullable=False, default=False, server_default='0') class System(Base): diff --git a/app/models/proxy.py b/app/models/proxy.py index bef62f36..c83ff9c2 100644 --- a/app/models/proxy.py +++ b/app/models/proxy.py @@ -149,6 +149,7 @@ class ProxyHost(BaseModel): is_disabled: Union[bool, None] = None mux_enable: Union[bool, None] = None fragment_setting: Optional[str] = Field(None, nullable=True) + random_user_agent: Union[bool, None] = None class Config: orm_mode = True diff --git a/app/subscription/share.py b/app/subscription/share.py index cd6e3869..4d12de41 100644 --- a/app/subscription/share.py +++ b/app/subscription/share.py @@ -282,7 +282,8 @@ def process_inbounds_and_tags( "ais": host["allowinsecure"] or inbound.get("allowinsecure", ""), "mux_enable": host["mux_enable"], - "fragment_setting": host["fragment_setting"] + "fragment_setting": host["fragment_setting"], + "random_user_agent": host["random_user_agent"], } ) diff --git a/app/subscription/singbox.py b/app/subscription/singbox.py index 7310baf8..5b5ffe8c 100644 --- a/app/subscription/singbox.py +++ b/app/subscription/singbox.py @@ -1,8 +1,9 @@ import json +from random import choice from app.templates import render_template from app.subscription.funcs import get_grpc_gun -from config import SINGBOX_SUBSCRIPTION_TEMPLATE, MUX_TEMPLATE +from config import SINGBOX_SUBSCRIPTION_TEMPLATE, MUX_TEMPLATE, USER_AGENT_TEMPLATE class SingBoxConfiguration(str): @@ -11,6 +12,13 @@ def __init__(self): template = render_template(SINGBOX_SUBSCRIPTION_TEMPLATE) self.config = json.loads(template) self.mux_template = render_template(MUX_TEMPLATE) + temp_user_agent_data = render_template(USER_AGENT_TEMPLATE) + user_agent_data = json.loads(temp_user_agent_data) + + if 'list' in user_agent_data and isinstance(user_agent_data['list'], list): + self.user_agent_list = user_agent_data['list'] + else: + self.user_agent_list = [] def add_outbound(self, outbound_data): self.config["outbounds"].append(outbound_data) @@ -65,8 +73,8 @@ def tls_config(sni=None, fp=None, tls=None, pbk=None, return config - @staticmethod - def transport_config(transport_type='', + def transport_config(self, + transport_type='', host='', path='', method='', @@ -74,7 +82,8 @@ def transport_config(transport_type='', ping_timeout="15s", max_early_data=None, early_data_header_name=None, - permit_without_stream=False): + permit_without_stream=False, + random_user_agent: bool = False): transport_config = {} @@ -87,8 +96,12 @@ def transport_config(transport_type='', transport_config['path'] = path if method: transport_config['method'] = method + if host or random_user_agent: + transport_config['headers'] = {} if host: transport_config["host"] = [host] + if random_user_agent: + transport_config['headers']['User-Agent'] = choice(self.user_agent_list) if idle_timeout: transport_config['idle_timeout'] = idle_timeout if ping_timeout: @@ -97,8 +110,12 @@ def transport_config(transport_type='', elif transport_type == "ws": if path: transport_config['path'] = path + if host or random_user_agent: + transport_config['headers'] = {} if host: transport_config['headers'] = {'Host': host} + if random_user_agent: + transport_config['headers']['User-Agent'] = choice(self.user_agent_list) if max_early_data is not None: transport_config['max_early_data'] = max_early_data if early_data_header_name: @@ -118,6 +135,9 @@ def transport_config(transport_type='', transport_config['host'] = host if path: transport_config['path'] = path + if random_user_agent: + transport_config['headers'] = {} + transport_config['headers']['User-Agent'] = choice(self.user_agent_list) return transport_config @@ -139,6 +159,7 @@ def make_outbound(self, headers='', ais='', mux_enable: bool = False, + random_user_agent: bool = False, ): config = { @@ -173,7 +194,8 @@ def make_outbound(self, host=host, path=path, max_early_data=max_early_data, - early_data_header_name=early_data_header_name + early_data_header_name=early_data_header_name, + random_user_agent=random_user_agent, ) else: config["network"] = net @@ -215,7 +237,8 @@ def add(self, remark: str, address: str, inbound: dict, settings: dict): sid=inbound.get('sid', ''), headers=inbound['header_type'], ais=inbound.get('ais', ''), - mux_enable=inbound.get('mux_enable', False)) + mux_enable=inbound.get('mux_enable', False), + random_user_agent=inbound.get('random_user_agent', False),) if inbound['protocol'] == 'vmess': outbound['uuid'] = settings['id'] diff --git a/app/subscription/v2ray.py b/app/subscription/v2ray.py index ca9d900e..625432db 100644 --- a/app/subscription/v2ray.py +++ b/app/subscription/v2ray.py @@ -1,5 +1,6 @@ import base64 import json +from random import choice import urllib.parse as urlparse from typing import Union from uuid import UUID @@ -8,7 +9,7 @@ from app.subscription.funcs import get_grpc_gun, get_grpc_multi from app.templates import render_template -from config import (MUX_TEMPLATE, V2RAY_SUBSCRIPTION_TEMPLATE) +from config import (MUX_TEMPLATE, V2RAY_SUBSCRIPTION_TEMPLATE, USER_AGENT_TEMPLATE) class V2rayShareLink(str): @@ -341,6 +342,13 @@ def __init__(self): self.config = [] self.template = render_template(V2RAY_SUBSCRIPTION_TEMPLATE) self.mux_template = render_template(MUX_TEMPLATE) + temp_user_agent_data = render_template(USER_AGENT_TEMPLATE) + user_agent_data = json.loads(temp_user_agent_data) + + if 'list' in user_agent_data and isinstance(user_agent_data['list'], list): + self.user_agent_list = user_agent_data['list'] + else: + self.user_agent_list = [] def add_config(self, remarks, outbounds): json_template = json.loads(self.template) @@ -390,8 +398,8 @@ def reality_config(sni=None, fp=None, pbk=None, sid=None, spx=None): return realitySettings - @staticmethod - def ws_config(path=None, host=None): + + def ws_config(self, path=None, host=None, random_user_agent=None): wsSettings = {} wsSettings["headers"] = {} @@ -399,17 +407,21 @@ def ws_config(path=None, host=None): wsSettings["path"] = path if host: wsSettings["headers"]["Host"] = host + if random_user_agent: + wsSettings["headers"]["User-Agent"] = choice(self.user_agent_list) return wsSettings - @staticmethod - def httpupgrade_config(path=None, host=None): + def httpupgrade_config(self, path=None, host=None, random_user_agent=None): httpupgradeSettings = {} + httpupgradeSettings["headers"] = {} if path: httpupgradeSettings["path"] = path if host: httpupgradeSettings["host"] = host + if random_user_agent: + httpupgradeSettings["headers"]["User-Agent"] = choice(self.user_agent_list) return httpupgradeSettings @@ -427,8 +439,7 @@ def grpc_config(path=None, multiMode=False): return grpcSettings - @staticmethod - def tcp_http_config(path=None, host=None): + def tcp_http_config(self, path=None, host=None, random_user_agent=None): tcpSettings = {} if any((path, host)): @@ -440,7 +451,6 @@ def tcp_http_config(path=None, host=None): tcpSettings["header"]["request"]["headers"] = {} tcpSettings["header"]["request"]["method"] = "GET" - tcpSettings["header"]["request"]["headers"]["User-Agent"] = [] tcpSettings["header"]["request"]["headers"]["Accept-Encoding"] = ["gzip, deflate"] tcpSettings["header"]["request"]["headers"]["Connection"] = ["keep-alive"] tcpSettings["header"]["request"]["headers"]["Pragma"] = "no-cache" @@ -451,12 +461,17 @@ def tcp_http_config(path=None, host=None): if host: tcpSettings["header"]["request"]["headers"]["Host"] = [host] + if random_user_agent: + tcpSettings["header"]["request"]["headers"]["User-Agent"] = [choice(self.user_agent_list)] + else: + tcpSettings["header"]["request"]["headers"]["User-Agent"] = [] + return tcpSettings - @staticmethod - def h2_config(path=None, host=None): + def h2_config(self, path=None, host=None, random_user_agent=None): httpSettings = {} + httpSettings["headers"] = {} if path: httpSettings["path"] = path else: @@ -464,7 +479,9 @@ def h2_config(path=None, host=None): if host: httpSettings["host"] = [host] else: - httpSettings["host"] = {} + httpSettings["host"] = [] + if random_user_agent: + httpSettings["headers"]["User-Agent"] = [choice(self.user_agent_list)] return httpSettings @@ -647,24 +664,25 @@ def make_stream_setting(self, ais='', dialer_proxy='', multiMode: bool = False, + random_user_agent: bool = False, ): if net == "ws": - network_setting = self.ws_config(path=path, host=host) + network_setting = self.ws_config(path=path, host=host, random_user_agent=random_user_agent) elif net == "grpc": network_setting = self.grpc_config(path=path, multiMode=multiMode) elif net == "h2": - network_setting = self.h2_config(path=path, host=host) + network_setting = self.h2_config(path=path, host=host, random_user_agent=random_user_agent) elif net == "kcp": network_setting = self.kcp_config( path=path, host=host, header=headers) elif net == "tcp": - network_setting = self.tcp_http_config(path=path, host=host) + network_setting = self.tcp_http_config(path=path, host=host, random_user_agent=random_user_agent) elif net == "quic": network_setting = self.quic_config( path=path, host=host, header=headers) elif net == "httpupgrade": - network_setting = self.httpupgrade_config(path=path, host=host) + network_setting = self.httpupgrade_config(path=path, host=host, random_user_agent=random_user_agent) if tls == "tls": tls_settings = self.tls_config(sni=sni, fp=fp, alpn=alpn, ais=ais) @@ -769,6 +787,7 @@ def add(self, remark: str, address: str, inbound: dict, settings: dict): ais=inbound.get('ais', ''), dialer_proxy=dialer_proxy, multiMode=multi_mode, + random_user_agent=inbound.get('random_user_agent', False), ) mux_json = json.loads(self.mux_template) diff --git a/app/templates/user_agent/default.json b/app/templates/user_agent/default.json new file mode 100644 index 00000000..abb85644 --- /dev/null +++ b/app/templates/user_agent/default.json @@ -0,0 +1,104 @@ +{ + "list":[ + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36", + "Mozilla/5.0 (iPhone; CPU iPhone OS 17_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4.1 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36 PageSpeedPlus/1.0.0", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0", + "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Mobile Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:126.0) Gecko/20100101 Firefox/126.0", + "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36", + "Mozilla/5.0 (iPhone; CPU iPhone OS 17_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4.1 Safari/605.1.15", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 11.6; rv:92.0) Gecko/20100101 Firefox/92.0", + "Mozilla/5.0 (iPhone; CPU iPhone OS 16_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) obsidian/1.4.14 Chrome/114.0.5735.289 Electron/25.8.1 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:126.0) Gecko/20100101 Firefox/126.0", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15", + "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Mobile Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/25.0 Chrome/121.0.0.0 Mobile Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 Firefox/125.0", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Mobile Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:125.0) Gecko/20100101 Firefox/125.0", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) obsidian/1.4.16 Chrome/114.0.5735.289 Electron/25.8.1 Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Mobile Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36", + "Mozilla/5.0 (iPhone; CPU iPhone OS 17_2_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Safari/605.1.15", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) obsidian/1.5.3 Chrome/114.0.5735.289 Electron/25.8.1 Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Safari/605.1.15", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36", + "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2.1 Safari/605.1.15", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) obsidian/1.5.12 Chrome/120.0.6099.283 Electron/28.2.3 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) obsidian/1.4.16 Chrome/114.0.5735.289 Electron/25.8.1 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Mobile Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 OPR/109.0.0.0", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Safari/605.1.15", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.3.1 Safari/605.1.15", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) obsidian/1.4.13 Chrome/114.0.5735.289 Electron/25.8.1 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15", + "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0", + "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (iPhone; CPU iPhone OS 17_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.3 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (iPhone; CPU iPhone OS 16_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (iPhone; CPU iPhone OS 17_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.3.1 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.3 Safari/605.1.15", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) obsidian/1.4.13 Chrome/114.0.5735.289 Electron/25.8.1 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15", + "Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.6.1 Safari/605.1.15", + "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36", + "Mozilla/5.0 (iPhone; CPU iPhone OS 17_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1.1 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0", + "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) obsidian/1.5.12 Chrome/120.0.6099.283 Electron/28.2.3 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1.2 Safari/605.1.15", + "Mozilla/5.0 (iPhone; CPU iPhone OS 16_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.2 Mobile/15E148 Safari/604.1", + "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Safari/605.1.15", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:124.0) Gecko/20100101 Firefox/124.0", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) obsidian/1.5.3 Chrome/114.0.5735.289 Electron/25.8.1 Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.3 Safari/605.1.15", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0", + "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Mobile Safari/537.36", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", + "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/24.0 Chrome/117.0.0.0 Mobile Safari/537.36" + ] +} \ No newline at end of file diff --git a/app/xray/__init__.py b/app/xray/__init__.py index 8f13d942..1bc23fe6 100644 --- a/app/xray/__init__.py +++ b/app/xray/__init__.py @@ -61,7 +61,8 @@ def hosts(storage: dict): else host.security.value, "allowinsecure": host.allowinsecure, "mux_enable": host.mux_enable, - "fragment_setting": host.fragment_setting + "fragment_setting": host.fragment_setting, + "random_user_agent": host.random_user_agent, } for host in inbound_hosts if not host.is_disabled ] diff --git a/config.py b/config.py index fa22f994..1565bc90 100755 --- a/config.py +++ b/config.py @@ -50,6 +50,8 @@ SINGBOX_SUBSCRIPTION_TEMPLATE = config("SINGBOX_SUBSCRIPTION_TEMPLATE", default="singbox/default.json") MUX_TEMPLATE = config("MUX_TEMPLATE", default="mux/default.json") V2RAY_SUBSCRIPTION_TEMPLATE = config("V2RAY_SUBSCRIPTION_TEMPLATE", default="v2ray/default.json") +USER_AGENT_TEMPLATE = config("USER_AGENT_TEMPLATE", default="user_agent/default.json") + USE_CUSTOM_JSON_DEFAULT = config("USE_CUSTOM_JSON_DEFAULT", default=False, cast=bool) USE_CUSTOM_JSON_FOR_V2RAYN = config("USE_CUSTOM_JSON_FOR_V2RAYN", default=False, cast=bool)