Browse Source

update: complete filter module

master
dnomd343 2 years ago
parent
commit
ae84011188
  1. 22
      Basis/Filter.py
  2. 61
      Basis/Functions.py
  3. 55
      Filter/Plugin.py
  4. 29
      Filter/Shadowsocks.py
  5. 21
      demo.py

22
Basis/Filter.py

@ -54,7 +54,7 @@ filterObject = {
'errMsg': { 'errMsg': {
'type': str, 'type': str,
'optional': True, # `errMsg` is not force require 'optional': True, # `errMsg` is not force require
'default': 'filter error', 'default': 'Filter error',
'allowNone': False, # `errMsg` couldn't be None 'allowNone': False, # `errMsg` couldn't be None
} }
} }
@ -75,7 +75,7 @@ def Filter(raw: dict, rules: dict) -> dict:
# pretreatment process (raw --[copy / default value]--> data) # pretreatment process (raw --[copy / default value]--> data)
if key not in raw: # key not exist if key not in raw: # key not exist
if not rule['optional']: # force require key not exist if not rule['optional']: # force require key not exist
raise RuntimeError('Miss `%s` field' % key) raise RuntimeError('Missing `%s` field' % key)
data[key] = rule['default'] # set default value data[key] = rule['default'] # set default value
else: # key exist else: # key exist
data[key] = raw[key] data[key] = raw[key]
@ -97,11 +97,21 @@ def Filter(raw: dict, rules: dict) -> dict:
elif type(data[key]) not in rule['type']: # type not in allow list elif type(data[key]) not in rule['type']: # type not in allow list
raise RuntimeError('Invalid `%s` field' % key) raise RuntimeError('Invalid `%s` field' % key)
elif type(rule['type']) == dict: # check subObject elif type(rule['type']) == dict: # check subObject
if type(data[key]) != dict:
raise RuntimeError('Invalid sub object in `%s`' % key) # subObject content should be dict
if not rule['multiSub']: # single subObject if not rule['multiSub']: # single subObject
data[key] = Filter(data[key], rule['type']) subRules = rule['type']
else: # multi subObject else: # multi subObject
# TODO: multi sub filter if rule['indexKey'] not in data[key]: # confirm index key exist
pass raise RuntimeError('Index key not found in `%s`' % key)
subType = data[key][rule['indexKey']]
if subType not in rule['type']: # confirm subObject rule exist
raise RuntimeError('Unknown index `%s` in key `%s`' % (subType, key))
subRules = rule['type'][subType]
try:
data[key] = Filter(data[key], subRules)
except RuntimeError as exp:
raise RuntimeError('%s (in `%s`)' % (exp, key)) # add located info
continue continue
elif rule['type'] != any: # type == any -> skip type filter elif rule['type'] != any: # type == any -> skip type filter
raise RuntimeError('Unknown `type` in rules') raise RuntimeError('Unknown `type` in rules')
@ -117,4 +127,4 @@ def rulesFilter(rules: dict) -> dict:
return result return result
filterObject = rulesFilter(filterObject) # format itself filterObject = rulesFilter(filterObject) # self-format

61
Basis/Functions.py

@ -10,6 +10,17 @@ from IPy import IP
from Basis.Logger import logging from Basis.Logger import logging
def isHost(raw) -> bool:
# TODO: isHost function
return True
def isPort(port: int) -> bool:
if type(port) != int:
return False
return 1 <= port <= 65535 # 1 ~ 65535
def md5Sum(data: str, encode: str = 'utf-8') -> str: def md5Sum(data: str, encode: str = 'utf-8') -> str:
return hashlib.md5(data.encode(encoding = encode)).hexdigest() return hashlib.md5(data.encode(encoding = encode)).hexdigest()
@ -42,6 +53,36 @@ def genUUID() -> str: # generate uuid v5
)) ))
def toInt(raw) -> int:
try:
return int(raw)
except:
raise RuntimeError('Unable convert to int')
def toStr(raw, acceptNone: bool = True) -> str:
if raw is None and acceptNone: # None -> ''
return ''
if isinstance(raw, bytes): # bytes -> str
return str(raw, encoding = 'utf-8')
try:
return str(raw)
except:
raise RuntimeError('Unable convert to str')
def toBool(raw) -> bool:
if isinstance(raw, (bool, int, float)):
return bool(raw)
try:
raw = toStr(raw).strip().lower()
if raw in ['true', 'false']:
return True if raw == 'true' else False
return int(raw) != 0
except:
raise RuntimeError('Unable convert to bool')
def getAvailablePort(rangeStart: int = 1024, rangeEnd: int = 65535, waitTime: int = 10) -> int: # get available port def getAvailablePort(rangeStart: int = 1024, rangeEnd: int = 65535, waitTime: int = 10) -> int: # get available port
if rangeStart > rangeEnd or rangeStart < 1 or rangeEnd > 65535: if rangeStart > rangeEnd or rangeStart < 1 or rangeEnd > 65535:
raise RuntimeError('Invalid port range') raise RuntimeError('Invalid port range')
@ -86,23 +127,3 @@ def networkStatus() -> list: # get all network connections
}) })
logging.debug('Network status -> found %i connections' % len(result)) logging.debug('Network status -> found %i connections' % len(result))
return result return result
def toInt(raw) -> int:
pass
def toStr(raw) -> str:
pass
def toBool(raw) -> bool:
pass
def isHost(raw) -> bool:
pass
def isPort(raw) -> bool:
pass

55
Filter/Plugin.py

@ -1,5 +1,58 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import copy
from Basis.Functions import toStr
from Basis.Filter import rulesFilter
from Basis.Constant import pluginClients
pluginAlias = {
'obfs-local': {'obfs', 'simple-obfs'},
'simple-tls': {'tls', 'simple-tls'},
'v2ray-plugin': {'v2ray'},
'xray-plugin': {'xray'},
'kcptun-client': {'kcptun'},
'gost-plugin': {'gost'},
'ck-client': {'ck', 'cloak'},
'gq-client': {'gq', 'goquiet', 'go-quiet'},
'mtt-client': {'mtt', 'mos-tls-tunnel'},
'rabbit-plugin': {'rabbit', 'rabbit-tcp'},
'qtun-client': {'qtun'},
'gun-plugin': {'gun'},
}
pluginObject = rulesFilter({
'type': {
'type': str,
'format': lambda s: pluginFormat(toStr(s)),
'filter': lambda s: s in pluginClients,
'errMsg': 'Unknown SIP003 plugin'
},
'param': {
'optional': True,
'default': '',
'type': str,
'format': toStr,
'errMsg': 'Invalid SIP003 param'
}
})
def loadAlias() -> None:
for plugin in pluginAlias:
for alias in copy.copy(pluginAlias[plugin]):
pluginAlias[plugin].update({ # better compatibility
alias + '-local', alias + '-plugin',
alias + '-client', alias + '-server',
})
def pluginFormat(pluginName: str) -> str: def pluginFormat(pluginName: str) -> str:
return pluginName pluginName = pluginName.strip().lower().replace('_', '-')
for plugin, alias in pluginAlias.items():
if pluginName in alias:
return plugin
return pluginName # alias not found
loadAlias()

29
Filter/Shadowsocks.py

@ -1,27 +1,11 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from Filter.Plugin import pluginFormat from Basis.Filter import rulesFilter
from Filter.Plugin import pluginObject
from Basis.Constant import ssAllMethods
from Basis.Functions import toInt, toStr from Basis.Functions import toInt, toStr
from Basis.Functions import isHost, isPort from Basis.Functions import isHost, isPort
from Basis.Filter import Filter, rulesFilter
from Basis.Constant import ssMethods, pluginClients
pluginObject = rulesFilter({
'type': {
'type': str,
'format': lambda s: pluginFormat(toStr(s).strip().lower()),
'filter': lambda s: s in pluginClients,
'errMsg': 'Unknown SIP003 plugin'
},
'param': {
'optional': False,
'default': '',
'type': str,
'format': toStr,
'errMsg': 'Invalid SIP003 param'
}
})
ssObject = rulesFilter({ ssObject = rulesFilter({
'server': { 'server': {
@ -39,7 +23,7 @@ ssObject = rulesFilter({
'method': { 'method': {
'type': str, 'type': str,
'format': lambda s: toStr(s).strip().lower().replace('_', '-'), 'format': lambda s: toStr(s).strip().lower().replace('_', '-'),
'filter': lambda s: s in ssMethods, 'filter': lambda s: s in ssAllMethods,
'errMsg': 'Unknown Shadowsocks method' 'errMsg': 'Unknown Shadowsocks method'
}, },
'passwd': { 'passwd': {
@ -48,13 +32,10 @@ ssObject = rulesFilter({
'errMsg': 'Invalid password content' 'errMsg': 'Invalid password content'
}, },
'plugin': { 'plugin': {
'optional': False, 'optional': True,
'default': None, 'default': None,
'allowNone': True, 'allowNone': True,
'type': pluginObject, 'type': pluginObject,
'errMsg': 'Invalid pluginObject' 'errMsg': 'Invalid pluginObject'
} }
}) })
from pprint import pprint
pprint(ssObject, sort_dicts = False)

21
demo.py

@ -1,7 +1,22 @@
#!/usr/bin/env python #!/usr/bin/env python
import Filter.Shadowsocks from pprint import pprint
from Basis.Filter import Filter
from Basis.Filter import filterObject
from Filter.Shadowsocks import ssObject
# from pprint import pprint # pprint(ssObject, sort_dicts = False)
# from Basis.Filter import filterObject
# pprint(filterObject, sort_dicts = False) # pprint(filterObject, sort_dicts = False)
ssProxy = {
'server': '1.1.1.1',
'port': '12345',
'method': 'none',
'passwd': 'dnomd343',
'plugin': {
'type': 'obfs',
}
}
ret = Filter(ssProxy, ssObject)
pprint(ret, sort_dicts = False)

Loading…
Cancel
Save