From b462eb18bce2ca77780e3b8fbd83d8fe3e5e27f2 Mon Sep 17 00:00:00 2001 From: Dnomd343 Date: Sun, 20 Feb 2022 22:40:03 +0800 Subject: [PATCH] refactor: new ProxyFilter --- ProxyFilter/Plugin.py | 4 +- ProxyFilter/Shadowsocks.py | 104 +++++++++++------ ProxyFilter/ShadowsocksR.py | 222 +++++++++++++++++++++--------------- ProxyFilter/__init__.py | 2 +- ProxyFilter/baseFunc.py | 17 ++- ProxyFilter/filter.py | 9 +- 6 files changed, 215 insertions(+), 143 deletions(-) diff --git a/ProxyFilter/Plugin.py b/ProxyFilter/Plugin.py index 12e2244..9de5b1c 100644 --- a/ProxyFilter/Plugin.py +++ b/ProxyFilter/Plugin.py @@ -114,8 +114,8 @@ pluginAlias = { # 插件别名 def pluginFormat(plugin): # 插件格式化 plugin = plugin.replace('_', '-').lower().strip() - if not plugin in pluginList: # 非标插件名 + if plugin not in pluginList: # 非标插件名 for pluginName in pluginAlias: if plugin in pluginAlias[pluginName]: # 匹配别名列表 return pluginName - return plugin + return plugin # 匹配不到时返回原值 diff --git a/ProxyFilter/Shadowsocks.py b/ProxyFilter/Shadowsocks.py index a258dc7..b624498 100644 --- a/ProxyFilter/Shadowsocks.py +++ b/ProxyFilter/Shadowsocks.py @@ -1,10 +1,41 @@ #!/usr/bin/python # -*- coding:utf-8 -*- +""" + +{ + 'server': '...', + 'port': ..., + 'method': '...', + 'passwd': '...', + 'plugin': pluginObject +} + +server (str) -> required + +port (int or str) -> required + +method (str) -> required + +passwd (str) -> required + +plugin (None or dict) -> optional + +pluginObject: { + 'type': '...', + 'param': '...' +} + +type (str) -> optional + +param (str) -> optional + +""" + from ProxyFilter import baseFunc from ProxyFilter import Plugin as sip003 -ssMethodList = [ +ssMethodList = [ # Shadowsocks加密方式 'aes-128-gcm', 'aes-192-gcm', 'aes-256-gcm', @@ -56,7 +87,7 @@ ssMethodList = [ 'xchacha20-ietf-poly1305' ] -pluginList = [ +pluginList = [ # SIP003插件列表 'obfs-local', 'simple-tls', 'v2ray-plugin', @@ -71,18 +102,32 @@ pluginList = [ 'gun-plugin' ] -def __ssFormat(raw): # 容错性格式化 +def __ssFill(raw: dict) -> dict: # 补全可选值 + try: + if 'plugin' not in raw: + raw['plugin'] = None + if raw['plugin'] is not None: + if 'type' not in raw['plugin']: + raw['plugin']['type'] = '' + if 'param' not in raw['plugin']: + raw['plugin']['param'] = '' + except: + pass + return raw + +def __ssFormat(raw: dict) -> dict: # 容错性格式化 try: raw['server'] = raw['server'].strip() raw['port'] = int(raw['port']) raw['method'] = raw['method'].replace('_', '-').lower().strip() - raw['plugin'] = sip003.pluginFormat(raw['plugin']) + if raw['plugin'] is not None: + raw['plugin']['type'] = sip003.pluginFormat(raw['plugin']['type']) except: pass return raw -def ssFilter(raw): - ''' +def ssFilter(raw: dict) -> tuple[bool, str or dict]: + """ Shadowsocks节点合法性检查 不合法: @@ -91,51 +136,46 @@ def ssFilter(raw): 合法: return True, { 'type': 'ss', - 'server': '...', - 'port': ..., - 'password': '...', - 'method": '...', - 'plugin": '...', - 'pluginParam": '...' + ... } - ''' + """ try: - result = {} - result['type'] = 'ss' - raw = __ssFormat(raw) - - if not 'server' in raw: + if 'server' not in raw: # 必选值检查 return False, 'Missing `server` option' - if not 'port' in raw: + if 'port' not in raw: return False, 'Missing `port` option' - if not 'password' in raw: - return False, 'Missing `password` option' - if not 'method' in raw: + if 'method' not in raw: return False, 'Missing `method` option' + if 'passwd' not in raw: + return False, 'Missing `passwd` option' + raw = __ssFormat(__ssFill(raw)) # 预处理 + result = {'type': 'ss'} if baseFunc.isHost(raw['server']): - result['server'] = raw['server'] + result['server'] = raw['server'] # server else: return False, 'Illegal `server` option' if baseFunc.isPort(raw['port']): - result['port'] = raw['port'] + result['port'] = raw['port'] # port else: return False, 'Illegal `port` option' - result['password'] = raw['password'] if raw['method'] in ssMethodList: - result['method'] = raw['method'] + result['method'] = raw['method'] # method else: return False, 'Unknown Shadowsocks method' + result['passwd'] = raw['passwd'] # passwd - if (not 'plugin' in raw) or raw['plugin'] == '': - result['plugin'] = '' - result['pluginParam'] = '' + if raw['plugin'] is None or raw['plugin']['type'] in [None, '']: + plugin = None else: - if raw['plugin'] in pluginList: - result['plugin'] = raw['plugin'] - result['pluginParam'] = raw['pluginParam'] + if raw['plugin']['type'] in pluginList: + plugin = { + 'type': raw['plugin']['type'], + 'param': raw['plugin']['param'] + } else: return False, 'Unknown sip003 plugin' + result['plugin'] = plugin except: return False, 'Unknown error' return True, result diff --git a/ProxyFilter/ShadowsocksR.py b/ProxyFilter/ShadowsocksR.py index 15ab780..c37c94e 100644 --- a/ProxyFilter/ShadowsocksR.py +++ b/ProxyFilter/ShadowsocksR.py @@ -1,94 +1,136 @@ #!/usr/bin/python # -*- coding:utf-8 -*- +""" +{ + 'server': '...', + 'port': ..., + 'method': '...', + 'passwd': '...', + 'protocol': '...', + 'protocolParam': '...', + 'obfs': '...', + 'obfsParam': '...' +} + +server (str) -> required + +port (int or str) -> required + +method (str) -> required + +passwd (str) -> required + +protocol (str) -> optional + +protocolParam (str) -> optional + +obfs (str) -> optional + +obfsParam (str) -> optional + +""" + from ProxyFilter import baseFunc -ssrMethodList = [ - "aes-128-cfb", - "aes-192-cfb", - "aes-256-cfb", - "aes-128-cfb1", - "aes-192-cfb1", - "aes-256-cfb1", - "aes-128-cfb8", - "aes-192-cfb8", - "aes-256-cfb8", - "aes-128-ctr", - "aes-192-ctr", - "aes-256-ctr", - "aes-128-gcm", - "aes-192-gcm", - "aes-256-gcm", - "aes-128-ofb", - "aes-192-ofb", - "aes-256-ofb", - "camellia-128-cfb", - "camellia-192-cfb", - "camellia-256-cfb", - "none", - "table", - "rc4", - "rc4-md5", - "rc4-md5-6", - "bf-cfb", - "cast5-cfb", - "des-cfb", - "idea-cfb", - "seed-cfb", - "rc2-cfb", - "salsa20", - "xsalsa20", - "chacha20", - "xchacha20", - "chacha20-ietf", +ssrMethodList = [ # ShadowsocksR加密方式 + 'aes-128-cfb', + 'aes-192-cfb', + 'aes-256-cfb', + 'aes-128-cfb1', + 'aes-192-cfb1', + 'aes-256-cfb1', + 'aes-128-cfb8', + 'aes-192-cfb8', + 'aes-256-cfb8', + 'aes-128-ctr', + 'aes-192-ctr', + 'aes-256-ctr', + 'aes-128-gcm', + 'aes-192-gcm', + 'aes-256-gcm', + 'aes-128-ofb', + 'aes-192-ofb', + 'aes-256-ofb', + 'camellia-128-cfb', + 'camellia-192-cfb', + 'camellia-256-cfb', + 'none', + 'table', + 'rc4', + 'rc4-md5', + 'rc4-md5-6', + 'bf-cfb', + 'cast5-cfb', + 'des-cfb', + 'idea-cfb', + 'seed-cfb', + 'rc2-cfb', + 'salsa20', + 'xsalsa20', + 'chacha20', + 'xchacha20', + 'chacha20-ietf', ] -ssrProtocolList = [ - "origin", - "verify_sha1", - "verify_simple", - "verify_deflate", - "auth_simple", - "auth_sha1", - "auth_sha1_v2", - "auth_sha1_v4", - "auth_aes128", - "auth_aes128_md5", - "auth_aes128_sha1", - "auth_chain_a", - "auth_chain_b", - "auth_chain_c", - "auth_chain_d", - "auth_chain_e", - "auth_chain_f", +ssrProtocolList = [ # ShadowsocksR协议 + 'origin', + 'verify_sha1', + 'verify_simple', + 'verify_deflate', + 'auth_simple', + 'auth_sha1', + 'auth_sha1_v2', + 'auth_sha1_v4', + 'auth_aes128', + 'auth_aes128_md5', + 'auth_aes128_sha1', + 'auth_chain_a', + 'auth_chain_b', + 'auth_chain_c', + 'auth_chain_d', + 'auth_chain_e', + 'auth_chain_f', ] -ssrObfsList = [ - "plain", - "http_post", - "http_simple", - "tls_simple", - "tls1.2_ticket_auth", - "tls1.2_ticket_fastauth", - "random_head", +ssrObfsList = [ # ShadowsocksR混淆方式 + 'plain', + 'http_post', + 'http_simple', + 'tls_simple', + 'tls1.2_ticket_auth', + 'tls1.2_ticket_fastauth', + 'random_head', ] -def __ssrFormat(raw): # 容错性格式化 +def __ssrFill(raw: dict) -> dict: # 补全可选值 + try: + if 'protocol' not in raw: + raw['protocol'] = '' + if 'protocolParam' not in raw: + raw['protocolParam'] = '' + if 'obfs' not in raw: + raw['obfs'] = '' + if 'obfsParam' not in raw: + raw['obfsParam'] = '' + except: + pass + return raw + +def __ssrFormat(raw: dict) -> dict: # 容错性格式化 try: raw['server'] = raw['server'].strip() raw['port'] = int(raw['port']) raw['method'] = raw['method'].replace('_', '-').lower().strip() - if 'protocol' in raw: - raw['protocol'] = raw['protocol'].replace('-', '_').lower().strip() - if 'obfs' in raw: - raw['obfs'] = raw['obfs'].replace('-', '_').lower().strip() + raw['protocol'] = raw['protocol'].replace('-', '_').lower().strip() + raw['obfs'] = raw['obfs'].replace('-', '_').lower().strip() except: pass return raw -def ssrFilter(raw): - ''' +def ssrFilter(raw: dict) -> tuple[bool, str or dict]: + """ ShadowsocksR节点合法性检查 不合法: @@ -97,45 +139,37 @@ def ssrFilter(raw): 合法: return True, { 'type': 'ssr', - 'server': '...', - 'port': ..., - 'password': '...', - 'method": '...', - 'protocol': '...', - 'protocolParam': '...', - 'obfs': '...', - 'obfsParam': '...' + ... } - ''' + """ try: - result = {} - result['type'] = 'ssr' - raw = __ssrFormat(raw) - if not 'server' in raw: + if 'server' not in raw: # 必选值检查 return False, 'Missing `server` option' - if not 'port' in raw: + if 'port' not in raw: return False, 'Missing `port` option' - if not 'password' in raw: - return False, 'Missing `password` option' - if not 'method' in raw: + if 'method' not in raw: return False, 'Missing `method` option' + if 'passwd' not in raw: + return False, 'Missing `password` option' + raw = __ssrFormat(__ssrFill(raw)) # 预处理 + result = {'type': 'ssr'} if baseFunc.isHost(raw['server']): - result['server'] = raw['server'] + result['server'] = raw['server'] # server else: return False, 'Illegal `server` option' if baseFunc.isPort(raw['port']): - result['port'] = raw['port'] + result['port'] = raw['port'] # port else: return False, 'Illegal `port` option' - result['password'] = raw['password'] if raw['method'] in ssrMethodList: - result['method'] = raw['method'] + result['method'] = raw['method'] # method else: return False, 'Unknown ShadowsocksR method' + result['passwd'] = raw['passwd'] # passwd - if (not 'protocol' in raw) or raw['protocol'] == 'origin' or raw['protocol'] == '': + if raw['protocol'] in [None, '', 'origin']: # 默认协议 result['protocol'] = 'origin' result['protocolParam'] = '' else: @@ -145,7 +179,7 @@ def ssrFilter(raw): else: return False, 'Unknown ShadowsocksR protocol' - if (not 'obfs' in raw) or raw['obfs'] == 'plain' or raw['obfs'] == '': + if raw['obfs'] in [None, '', 'plain']: # 默认混淆 result['obfs'] = 'plain' result['obfsParam'] = '' else: diff --git a/ProxyFilter/__init__.py b/ProxyFilter/__init__.py index f7b8eb9..7198490 100644 --- a/ProxyFilter/__init__.py +++ b/ProxyFilter/__init__.py @@ -3,4 +3,4 @@ from ProxyFilter.filter import * -__all__ = [ 'filter' ] +__all__ = ['filte'] diff --git a/ProxyFilter/baseFunc.py b/ProxyFilter/baseFunc.py index c337552..1e4dea2 100644 --- a/ProxyFilter/baseFunc.py +++ b/ProxyFilter/baseFunc.py @@ -5,7 +5,7 @@ import re import IPy def isHost(host: str) -> bool: - ''' + """ 判断host是否合法 IPv4 / IPv6 / Domain @@ -13,7 +13,7 @@ def isHost(host: str) -> bool: 合法: return True 不合法: return False - ''' + """ try: IPy.IP(host) if host.find('/') != -1: # filter CIDR @@ -21,10 +21,10 @@ def isHost(host: str) -> bool: return True except: # not IP address pass - return (re.search(r'^(?=^.{3,255}$)[a-zA-Z0-9_][a-zA-Z0-9_-]{0,62}(\.[a-zA-Z0-9_][a-zA-Z0-9_-]{0,62})+$', host) != None) + return re.search(r'^(?=^.{3,255}$)[a-zA-Z0-9_][a-zA-Z0-9_-]{0,62}(\.[a-zA-Z0-9_][a-zA-Z0-9_-]{0,62})+$', host) is not None -def isPort(port) -> bool: - ''' +def isPort(port: int) -> bool: + """ 判断端口是否合法 1 ~ 65535 @@ -32,11 +32,10 @@ def isPort(port) -> bool: 合法: return True 不合法: return False - ''' + """ try: - if isinstance(port, (int, str)): - if int(port) >= 1 and int(port) <= 65535: - return True + if 1 <= port <= 65535: + return True except: # illegal pass return False diff --git a/ProxyFilter/filter.py b/ProxyFilter/filter.py index 54f4817..5933304 100644 --- a/ProxyFilter/filter.py +++ b/ProxyFilter/filter.py @@ -4,8 +4,8 @@ from ProxyFilter import Shadowsocks from ProxyFilter import ShadowsocksR -def filter(raw): - ''' +def filte(raw: dict) -> tuple[bool, str]: + """ 代理信息过滤并格式化 参数无效: @@ -17,10 +17,9 @@ def filter(raw): '...': '...', ... } - - ''' + """ try: - if not 'type' in raw: + if 'type' not in raw: return False, 'Missing `type` option' if raw['type'] == 'ss': return Shadowsocks.ssFilter(raw)