diff --git a/ProxyBuilder/Shadowsocks.py b/ProxyBuilder/Shadowsocks.py index 3950c76..b888635 100644 --- a/ProxyBuilder/Shadowsocks.py +++ b/ProxyBuilder/Shadowsocks.py @@ -206,8 +206,8 @@ def __ssFormatCheck(proxyInfo: dict) -> bool: # Shadowsocks参数检查 return False if 'plugin' not in proxyInfo: return False - plugin = proxyInfo['plugin'] - if isinstance(plugin, dict): # plugin -> dict / None + plugin = proxyInfo['plugin'] # plugin -> dict / None + if isinstance(plugin, dict): if 'type' not in plugin or not isinstance(plugin['type'], str): # plugin.type -> str return False if 'param' not in plugin or not isinstance(plugin['param'], str): # plugin.param -> str diff --git a/ProxyBuilder/builder.py b/ProxyBuilder/builder.py index af72d7b..d03170d 100644 --- a/ProxyBuilder/builder.py +++ b/ProxyBuilder/builder.py @@ -54,7 +54,7 @@ def __checkPortAvailable(port: int) -> bool: # 检测端口可用性 ipv6_udp.close() except: pass -def __genTaskFlag(length: int = 16) -> str: # 生成任务代号 +def __genTaskFlag(length: int = 16) -> str: # 生成任务标志 flag = '' for i in range(0, length): tmp = random.randint(0, 15) @@ -64,14 +64,14 @@ def __genTaskFlag(length: int = 16) -> str: # 生成任务代号 flag += str(tmp) # 0 ~ 9 return flag -def __getAvailablePort(rangeStart: int, rangeEnd: int) -> int or None: # 获取一个空闲端口 - if rangeStart > rangeEnd or rangeStart < 0 or rangeEnd > 65535: +def __getAvailablePort(rangeStart: int = 41952, rangeEnd: int = 65535) -> int or None: # 获取一个空闲端口 + if rangeStart > rangeEnd or rangeStart < 1 or rangeEnd > 65535: return None while True: port = random.randint(rangeStart, rangeEnd) # 随机选取 if __checkPortAvailable(port): return port - time.sleep(0.1) # 100ms + time.sleep(0.1) # wait for 100ms def build(proxyInfo: dict, configDir: str, portRangeStart: int = 1024, portRangeEnd: int = 65535) -> tuple[bool or None, str or dict]: diff --git a/ProxyDecoder/Shadowsocks.py b/ProxyDecoder/Shadowsocks.py index a4a1a4a..9ca1f0e 100644 --- a/ProxyDecoder/Shadowsocks.py +++ b/ProxyDecoder/Shadowsocks.py @@ -111,16 +111,20 @@ def __sip002Decode(url: str) -> dict or None: plugin = baseFunc.urlDecode(field.group(2)) # plugin参数 break if plugin.find(';') == -1: # plugin=... (无参数) - info['plugin'] = { + pluginField = { 'type': plugin, 'param': '' } else: # plugin=...;... (带参数) plugin = re.search(r'^([\S]*?);([\S]*)$', plugin) # 插件名;插件参数 - info['plugin'] = { + pluginField = { 'type': plugin.group(1), 'param': plugin.group(2) } + if pluginField['type'] == '': # 无插件情况 + info['plugin'] = None + else: + info['plugin'] = pluginField return info except: return None diff --git a/ProxyFilter/Shadowsocks.py b/ProxyFilter/Shadowsocks.py index f69ded2..21a57ad 100644 --- a/ProxyFilter/Shadowsocks.py +++ b/ProxyFilter/Shadowsocks.py @@ -76,8 +76,6 @@ def __ssFill(raw: dict) -> dict: # 补全可选值 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: @@ -89,13 +87,65 @@ def __ssFormat(raw: dict) -> dict: # 容错性格式化 raw['server'] = raw['server'].strip() raw['port'] = int(raw['port']) raw['method'] = raw['method'].replace('_', '-').lower().strip() + if isinstance(raw['plugin'], str): + raw['plugin'] = raw['plugin'].strip() + if raw['plugin'] == '': + raw['plugin'] = None + else: + raw['plugin'] = { + 'type': raw['plugin'], + 'param': '' + } if raw['plugin'] is not None: - raw['plugin']['type'] = sip003.pluginFormat(raw['plugin']['type']) + if isinstance(raw['plugin']['type'], str): + raw['plugin']['type'] = raw['plugin']['type'].strip() + if raw['plugin']['type'] in [None, '']: + raw['plugin'] = None + else: + raw['plugin']['type'] = sip003.pluginFormat(raw['plugin']['type']) except: pass return raw -def ssFilter(raw: dict) -> tuple[bool, str or dict]: +def __ssParamCheck(raw: dict) -> tuple[bool, str or None]: # 参数检查 + try: + if 'server' not in raw: + return False, 'Missing `server` option' + if 'port' not in raw: + return False, 'Missing `port` option' + if 'method' not in raw: + return False, 'Missing `method` option' + if 'passwd' not in raw: + return False, 'Missing `passwd` option' + if 'plugin' not in raw: + return False, 'Missing `plugin` option' + if raw['plugin'] is not None: + if 'type' not in raw['plugin']: + return False, 'Missing `plugin.type` option' + if 'param' not in raw['plugin']: + return False, 'Missing `plugin.param` option' + + if not isinstance(raw['server'], str): + return False, 'Illegal `server` option' + if not isinstance(raw['port'], int): + return False, 'Illegal `int` option' + if not isinstance(raw['method'], str): + return False, 'Illegal `method` option' + if not isinstance(raw['passwd'], str): + return False, 'Illegal `passwd` option' + if (raw['plugin'] is not None) and (not isinstance(raw['plugin'], dict)): + return False, 'Illegal `plugin` option' + + if raw['plugin'] is not None: + if not isinstance(raw['plugin']['type'], str): + return False, 'Illegal `plugin.type` option' + if not isinstance(raw['plugin']['param'], str): + return False, 'Illegal `plugin.param` option' + except: + return False, 'Unknown error' + return True, None + +def ssFilter(rawInfo: dict, isExtra: bool) -> tuple[bool, str or dict]: """ Shadowsocks节点合法性检查 @@ -109,17 +159,22 @@ def ssFilter(raw: dict) -> tuple[bool, str or dict]: } """ try: - if 'server' not in raw: # 必选值检查 - return False, 'Missing `server` option' - if 'port' not in raw: - return False, 'Missing `port` option' - if 'method' not in raw: - return False, 'Missing `method` option' - if 'passwd' not in raw: - return False, 'Missing `passwd` option' - raw = __ssFormat(__ssFill(raw)) # 预处理 + raw = rawInfo + raw = __ssFormat(__ssFill(raw)) # 预处理 + status, reason = __ssParamCheck(raw) # 参数检查 + if not status: # 参数有误 + return False, reason result = {'type': 'ss'} + if isExtra: # 携带额外参数 + if 'remark' not in raw: # 补全默认值 + raw['remark'] = '' + if raw['remark'] is None: # 容错格式化 + raw['remark'] = '' + if not isinstance(raw['remark'], str): # 参数检查 + return False, 'Illegal `remark` option' + result['remark'] = raw['remark'] + if baseFunc.isHost(raw['server']): result['server'] = raw['server'] # server else: @@ -134,7 +189,7 @@ def ssFilter(raw: dict) -> tuple[bool, str or dict]: return False, 'Unknown Shadowsocks method' result['passwd'] = raw['passwd'] # passwd - if raw['plugin'] is None or raw['plugin']['type'] in [None, '']: + if raw['plugin'] is None: plugin = None else: if raw['plugin']['type'] in pluginList: diff --git a/ProxyFilter/ShadowsocksR.py b/ProxyFilter/ShadowsocksR.py index 2d77d35..760368e 100644 --- a/ProxyFilter/ShadowsocksR.py +++ b/ProxyFilter/ShadowsocksR.py @@ -92,14 +92,60 @@ def __ssrFormat(raw: dict) -> dict: # 容错性格式化 raw['server'] = raw['server'].strip() raw['port'] = int(raw['port']) raw['method'] = raw['method'].replace('_', '-').lower().strip() + if raw['protocol'] is None: + raw['protocol'] = '' + if raw['protocolParam'] is None: + raw['protocolParam'] = '' + if raw['obfs'] is None: + raw['obfs'] = '' + if raw['obfsParam'] is None: + raw['obfsParam'] = '' raw['protocol'] = raw['protocol'].replace('-', '_').lower().strip() raw['obfs'] = raw['obfs'].replace('-', '_').lower().strip() except: pass return raw +def __ssrParamCheck(raw: dict) -> tuple[bool, str or None]: # 参数检查 + try: + if 'server' not in raw: + return False, 'Missing `server` option' + if 'port' not in raw: + return False, 'Missing `port` option' + if 'method' not in raw: + return False, 'Missing `method` option' + if 'passwd' not in raw: + return False, 'Missing `passwd` option' + if 'protocol' not in raw: + return False, 'Missing `protocol` option' + if 'protocolParam' not in raw: + return False, 'Missing `protocolParam` option' + if 'obfs' not in raw: + return False, 'Missing `obfs` option' + if 'obfsParam' not in raw: + return False, 'Missing `obfsParam` option' -def ssrFilter(raw: dict) -> tuple[bool, str or dict]: + if not isinstance(raw['server'], str): + return False, 'Illegal `server` option' + if not isinstance(raw['port'], int): + return False, 'Illegal `int` option' + if not isinstance(raw['method'], str): + return False, 'Illegal `method` option' + if not isinstance(raw['passwd'], str): + return False, 'Illegal `passwd` option' + if not isinstance(raw['protocol'], str): + return False, 'Illegal `protocol` option' + if not isinstance(raw['protocolParam'], str): + return False, 'Illegal `protocolParam` option' + if not isinstance(raw['obfs'], str): + return False, 'Illegal `obfs` option' + if not isinstance(raw['obfsParam'], str): + return False, 'Illegal `obfsParam` option' + except: + return False, 'Unknown error' + return True, None + +def ssrFilter(rawInfo: dict, isExtra: bool) -> tuple[bool, str or dict]: """ ShadowsocksR节点合法性检查 @@ -113,18 +159,29 @@ def ssrFilter(raw: dict) -> tuple[bool, str or dict]: } """ try: - - if 'server' not in raw: # 必选值检查 - return False, 'Missing `server` option' - if 'port' not in raw: - return False, 'Missing `port` option' - if 'method' not in raw: - return False, 'Missing `method` option' - if 'passwd' not in raw: - return False, 'Missing `password` option' - raw = __ssrFormat(__ssrFill(raw)) # 预处理 + raw = rawInfo + raw = __ssrFormat(__ssrFill(raw)) # 预处理 + status, reason = __ssrParamCheck(raw) # 参数检查 + if not status: # 参数有误 + return False, reason result = {'type': 'ssr'} + if isExtra: # 携带额外参数 + if 'remark' not in raw: # 补全默认值 + raw['remark'] = '' + if 'group' not in raw: + raw['group'] = '' + if raw['remark'] is None: # 容错格式化 + raw['remark'] = '' + if raw['group'] is None: + raw['group'] = '' + if not isinstance(raw['remark'], str): # 参数检查 + return False, 'Illegal `remark` option' + if not isinstance(raw['group'], str): + return False, 'Illegal `group` option' + result['remark'] = raw['remark'] + result['group'] = raw['group'] + if baseFunc.isHost(raw['server']): result['server'] = raw['server'] # server else: @@ -139,7 +196,7 @@ def ssrFilter(raw: dict) -> tuple[bool, str or dict]: return False, 'Unknown ShadowsocksR method' result['passwd'] = raw['passwd'] # passwd - if raw['protocol'] in [None, '', 'origin']: # 默认协议 + if raw['protocol'] in ['', 'origin']: # 默认协议 result['protocol'] = 'origin' result['protocolParam'] = '' else: @@ -149,7 +206,7 @@ def ssrFilter(raw: dict) -> tuple[bool, str or dict]: else: return False, 'Unknown ShadowsocksR protocol' - if raw['obfs'] in [None, '', 'plain']: # 默认混淆 + if raw['obfs'] in ['', 'plain']: # 默认混淆 result['obfs'] = 'plain' result['obfsParam'] = '' else: diff --git a/ProxyFilter/baseFunc.py b/ProxyFilter/baseFunc.py index 1e4dea2..e3e81b7 100644 --- a/ProxyFilter/baseFunc.py +++ b/ProxyFilter/baseFunc.py @@ -18,10 +18,15 @@ def isHost(host: str) -> bool: IPy.IP(host) if host.find('/') != -1: # filter CIDR return False - return True - except: # not IP address + return True # IP地址合法 + except: 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) is not None + try: + 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 + except: # 异常错误 + return False def isPort(port: int) -> bool: """ @@ -34,7 +39,7 @@ def isPort(port: int) -> bool: 不合法: return False """ try: - if 1 <= port <= 65535: + if 1 <= port <= 65535: # 1 ~ 65535 return True except: # illegal pass diff --git a/ProxyFilter/filter.py b/ProxyFilter/filter.py index 5933304..43413d2 100644 --- a/ProxyFilter/filter.py +++ b/ProxyFilter/filter.py @@ -4,7 +4,7 @@ from ProxyFilter import Shadowsocks from ProxyFilter import ShadowsocksR -def filte(raw: dict) -> tuple[bool, str]: +def filte(raw: dict, isExtra: bool = False) -> tuple[bool, str]: """ 代理信息过滤并格式化 @@ -13,7 +13,7 @@ def filte(raw: dict) -> tuple[bool, str]: 参数有效: return True, { - '...': '...', + 'type': '...', '...': '...', ... } @@ -22,9 +22,9 @@ def filte(raw: dict) -> tuple[bool, str]: if 'type' not in raw: return False, 'Missing `type` option' if raw['type'] == 'ss': - return Shadowsocks.ssFilter(raw) + return Shadowsocks.ssFilter(raw, isExtra) elif raw['type'] == 'ssr': - return ShadowsocksR.ssrFilter(raw) + return ShadowsocksR.ssrFilter(raw, isExtra) else: return False, 'Unknown proxy type' except: diff --git a/Web.py b/Web.py index dba30c4..574ef97 100644 --- a/Web.py +++ b/Web.py @@ -71,7 +71,7 @@ def addCheckTask(checkList: dict, proxyList: dict, priority: str, userId: str) - proxyList[i] = Decoder.decode(proxyList[i]) # 解码分享链接 if proxyList[i] is None: return genError('could not decode index ' + str(i)) - status, proxyList[i] = Filter.filte(proxyList[i]) # 节点信息检查 + status, proxyList[i] = Filter.filte(proxyList[i], isExtra = True) # 节点信息检查 if not status: # 节点不合法 return genError('index ' + str(i) + ': ' + proxyList[i]) diff --git a/docs/ProxyObject.md b/docs/ProxyObject.md index 555942a..d0a96e9 100644 --- a/docs/ProxyObject.md +++ b/docs/ProxyObject.md @@ -19,6 +19,16 @@ ## Shadowsocks +> **remark** +> +> + 类型:*str* +> +> + 说明:节点备注名称 +> +> + 缺省:'' +> +> + 可选值:不限 + ``` { 'type': 'ss', @@ -113,6 +123,27 @@ ## ShadowsocksR +> **remark** +> +> + 类型:*str* +> +> + 说明:节点备注名称 +> +> + 缺省:'' +> +> + 可选值:不限 +> + +> **group** +> +> + 类型:*str* +> +> + 说明:节点所属群组 +> +> + 缺省:'' +> +> + 可选值:不限 + ``` { 'type': 'ssr',