Add trojan import/export support

Signed-off-by: Loren Eteval <loren.eteval@proton.me>
This commit is contained in:
Loren Eteval
2023-09-14 18:19:06 +08:00
parent 04e67cff64
commit 3647a7e01f
6 changed files with 420 additions and 183 deletions
+42 -17
View File
@@ -38,12 +38,33 @@ class ExportLinkResultBox(MessageBox):
self.setWindowTitle(_('Export'))
if len(self.failureStr):
self.setIcon(MessageBox.Icon.Critical)
else:
self.setIcon(MessageBox.Icon.Information)
def getText(self):
text = self.getTextAll()
if len(text) <= 1000:
return text
else:
# Limited
if len(self.successStr) == 0:
return (
_('Export as QR code failed:')
if self.isQRCodeExport
else _('Export share link to clipboard failed:')
) + f'\n\n...'
elif len(self.failureStr) == 0:
return (
_('Export as QR code success:')
if self.isQRCodeExport
else _('Export share link to clipboard success:')
) + f'\n\n...'
else:
return (
_('Export as QR code partially success:')
if self.isQRCodeExport
else _('Export share link to clipboard partially success:')
) + f'\n\n...'
def getTextAll(self):
if len(self.successStr) == 0:
return (
(
@@ -151,6 +172,20 @@ def exportLink(selectedIndex):
return serverLink, successStr, failureStr
def showExportLinkResult(resultBox, successStr, failureStr):
resultBox.successStr = successStr
resultBox.failureStr = failureStr
resultBox.setText(resultBox.getText())
if len(successStr) == 0:
resultBox.setIcon(MessageBox.Icon.Critical)
else:
resultBox.setIcon(MessageBox.Icon.Information)
# Show the MessageBox and wait for user to close it
resultBox.exec()
class ExportLinkAction(Action):
def __init__(self, **kwargs):
super().__init__(_('Export Share Link To Clipboard'), **kwargs)
@@ -168,12 +203,7 @@ class ExportLinkAction(Action):
QApplication.clipboard().setText('\n'.join(serverLink))
self.exportLinkResult.successStr = successStr
self.exportLinkResult.failureStr = failureStr
self.exportLinkResult.setText(self.exportLinkResult.getText())
# Show the MessageBox and wait for user to close it
self.exportLinkResult.exec()
showExportLinkResult(self.exportLinkResult, successStr, failureStr)
class ExportQRCodeAction(Action):
@@ -201,12 +231,7 @@ class ExportQRCodeAction(Action):
self.exportQRCode.initTabWithData(list(zip(successStr, serverLink)))
self.exportQRCode.show()
self.exportLinkResult.successStr = successStr
self.exportLinkResult.failureStr = failureStr
self.exportLinkResult.setText(self.exportLinkResult.getText())
# Show the MessageBox and wait for user to close it
self.exportLinkResult.exec()
showExportLinkResult(self.exportLinkResult, successStr, failureStr)
class ExportJSONAction(Action):
+70 -3
View File
@@ -20,6 +20,7 @@ from Furious.Core.Configuration import (
XrayCoreConfiguration,
ProxyOutboundObject,
ProxyOutboundObjectSS,
ProxyOutboundObjectTrojan,
)
from Furious.Gui.Action import Action
from Furious.Widget.Widget import Menu, MessageBox
@@ -110,6 +111,15 @@ class ImportLinkResultBox(MessageBox):
self.setText(self.getText())
def getText(self):
text = self.getTextAll()
if len(text) <= 1000:
return text
else:
# Limited
return _('Import share link success: ') + f'\n\n...'
def getTextAll(self):
return (
_('Import share link success: ')
+ f'\n\n'
@@ -142,7 +152,9 @@ class ImportLinkAction(Action):
def showLinkErrorBox(self):
self.linkErrorBox.setWindowTitle(_('Import'))
if len(self.clipboard) > 1000:
# Limited
self.linkErrorBox.setText(_('Invalid share link.'))
self.linkErrorBox.setInformativeText('')
else:
@@ -359,6 +371,56 @@ class ImportLinkAction(Action):
return self.parseShareLinkSIP002(data)
@staticmethod
def parseShareLinkTrojan(data):
try:
parseResult = urllib.parse.urlparse(data)
queryObject = {
key: value for key, value in urllib.parse.parse_qsl(parseResult.query)
}
remark = urllib.parse.unquote(parseResult.fragment)
password, address, port = re.split(r'[@:]', parseResult.netloc)
type_ = queryObject.get('type', 'tcp')
security = queryObject.get('security', 'none')
# Remove redundant items
queryObject.pop('type', '')
queryObject.pop('security', '')
myJSON = XrayCoreConfiguration.build(
ProxyOutboundObjectTrojan(
password,
address,
int(port),
type_,
security,
# kwargs
**queryObject,
)
)
APP().ServerWidget.importServer(
remark,
ujson.dumps(
myJSON, indent=2, ensure_ascii=False, escape_forward_slashes=False
),
)
logger.info(
f'import share link from clipboard success. '
f'Remark: {remark}. Protocol: {Protocol.Trojan}'
)
return remark, True
except Exception:
# Any non-exit exceptions
return '', False
def parseShareLink(self, shareLink):
try:
myHead, myBody = shareLink.split('://')
@@ -378,13 +440,17 @@ class ImportLinkAction(Action):
else:
return self.parseShareLinkVMess(myJSON, isV2rayN=True)
if myHead.lower() == 'vless':
elif myHead.lower() == 'vless':
return self.parseShareLinkStandard('vless', shareLink)
if myHead.lower() == 'ss':
elif myHead.lower() == 'ss':
return self.parseShareLinkSS(shareLink)
return '', False
elif myHead.lower() == 'trojan':
return self.parseShareLinkTrojan(shareLink)
else:
return '', False
def triggeredCallback(self, checked):
self.clipboard = QApplication.clipboard().text().strip()
@@ -446,6 +512,7 @@ class ImportJSONAction(Action):
self.jsonErrorBox.setWindowTitle(_('Import'))
if len(self.clipboard) > 1000:
# Limited
self.jsonErrorBox.setText(_('Invalid JSON data.'))
self.jsonErrorBox.setInformativeText('')
else:
+275 -156
View File
@@ -18,7 +18,7 @@
from Furious.Core.Core import XrayCore
from Furious.Core.Intellisense import Intellisense
from Furious.Widget.Widget import MessageBox
from Furious.Utility.Constants import APPLICATION_NAME
from Furious.Utility.Constants import APPLICATION_NAME, PROXY_OUTBOUND_USER_EMAIL
from Furious.Utility.Utility import Base64Encoder, Protocol, bootstrapIcon
from Furious.Utility.Translator import gettext as _
@@ -42,6 +42,7 @@ class Configuration:
super().__init__(*args, **kwargs)
@staticmethod
@functools.lru_cache(32)
def toJSON(text):
return ujson.loads(text)
@@ -72,23 +73,20 @@ class Configuration:
def export(remark, ob):
if Intellisense.getCoreType(ob) == XrayCore.name():
def hasKey(obj, key):
return obj.get(key) is not None
def getStreamNetSettings(protocol, streamObject, netType):
def streamNetSettingsVMess(streamObject, netType):
kwargs = {}
netobj = streamObject[
ProxyOutboundObject.getStreamNetworkSettingsName(netType)
]
netobj = streamObject.get(ProxyOutboundObject.streamNetworkKey(netType))
if netobj is None:
return kwargs
def hasKey(key):
return netobj.get(key) is not None
if netType == 'tcp':
try:
if protocol == Protocol.VMess:
kwargs['type'] = netobj['header']['type']
if protocol == Protocol.VLESS:
kwargs['headerType'] = netobj['header']['type']
kwargs['type'] = netobj['header']['type']
except Exception:
# Any non-exit exceptions
@@ -97,17 +95,10 @@ class Configuration:
elif netType == 'kcp':
try:
# Get order matters here
if protocol == Protocol.VMess:
if hasKey(netobj, 'seed'):
kwargs['path'] = netobj['seed']
if hasKey('seed'):
kwargs['path'] = netobj['seed']
kwargs['type'] = netobj['header']['type']
if protocol == Protocol.VLESS:
if hasKey(netobj, 'seed'):
kwargs['seed'] = netobj['seed']
kwargs['headerType'] = netobj['header']['type']
kwargs['type'] = netobj['header']['type']
except Exception:
# Any non-exit exceptions
@@ -116,7 +107,7 @@ class Configuration:
elif netType == 'ws':
try:
# Get order matters here
if hasKey(netobj, 'path'):
if hasKey('path'):
kwargs['path'] = quote(netobj['path'])
if netobj['headers']['Host']:
@@ -129,7 +120,7 @@ class Configuration:
elif netType == 'h2' or netType == 'http':
try:
# Get order matters here
if hasKey(netobj, 'path'):
if hasKey('path'):
kwargs['path'] = quote(netobj['path'])
kwargs['host'] = quote(','.join(netobj['host']))
@@ -141,48 +132,108 @@ class Configuration:
elif netType == 'quic':
try:
# Get order matters here
if protocol == Protocol.VMess:
if hasKey(netobj, 'security'):
kwargs['host'] = netobj['security']
if hasKey('security'):
kwargs['host'] = netobj['security']
if hasKey(netobj, 'key'):
kwargs['path'] = quote(netobj['key'])
if hasKey('key'):
kwargs['path'] = quote(netobj['key'])
kwargs['type'] = netobj['header']['type']
if protocol == Protocol.VLESS:
if hasKey(netobj, 'security'):
kwargs['quicSecurity'] = netobj['security']
if hasKey(netobj, 'key'):
kwargs['path'] = quote(netobj['key'])
kwargs['headerType'] = netobj['header']['type']
kwargs['type'] = netobj['header']['type']
except Exception:
# Any non-exit exceptions
pass
elif netType == 'grpc':
if protocol == Protocol.VMess:
if hasKey(netobj, 'serviceName'):
kwargs['path'] = netobj['serviceName']
if protocol == Protocol.VLESS:
if hasKey(netobj, 'serviceName'):
kwargs['serviceName'] = netobj['serviceName']
if hasKey('serviceName'):
kwargs['path'] = netobj['serviceName']
return kwargs
def getStreamTLSSettings(streamObject, tlsType):
if tlsType == 'none':
return {}
def streamNetSettingsVLESS(streamObject, netType):
kwargs = {}
tlsobj = streamObject[
ProxyOutboundObject.getStreamTLSSettingsName(tlsType)
]
netobj = streamObject.get(ProxyOutboundObject.streamNetworkKey(netType))
if netobj is None:
return kwargs
def hasKey(key):
return netobj.get(key) is not None
if netType == 'tcp':
try:
kwargs['headerType'] = netobj['header']['type']
except Exception:
# Any non-exit exceptions
pass
elif netType == 'kcp':
try:
# Get order matters here
if hasKey('seed'):
kwargs['seed'] = netobj['seed']
kwargs['headerType'] = netobj['header']['type']
except Exception:
# Any non-exit exceptions
pass
elif netType == 'ws':
try:
# Get order matters here
if hasKey('path'):
kwargs['path'] = quote(netobj['path'])
if netobj['headers']['Host']:
kwargs['host'] = quote(netobj['headers']['Host'])
except Exception:
# Any non-exit exceptions
pass
elif netType == 'h2' or netType == 'http':
try:
# Get order matters here
if hasKey('path'):
kwargs['path'] = quote(netobj['path'])
kwargs['host'] = quote(','.join(netobj['host']))
except Exception:
# Any non-exit exceptions
pass
elif netType == 'quic':
try:
# Get order matters here
if hasKey('security'):
kwargs['quicSecurity'] = netobj['security']
if hasKey('key'):
kwargs['path'] = quote(netobj['key'])
kwargs['headerType'] = netobj['header']['type']
except Exception:
# Any non-exit exceptions
pass
elif netType == 'grpc':
if hasKey('serviceName'):
kwargs['serviceName'] = netobj['serviceName']
return kwargs
def streamTLSSettings(streamObject, tlsType):
kwargs = {}
if tlsType == 'none':
return kwargs
tlsobj = streamObject[ProxyOutboundObject.streamTLSKey(tlsType)]
if tlsType == 'reality' or tlsType == 'tls':
if tlsobj.get('fingerprint'):
@@ -207,109 +258,142 @@ class Configuration:
return kwargs
def getProxyOutboundObject():
for outboundObject in ob['outbounds']:
if outboundObject['tag'] == 'proxy':
return outboundObject
raise Exception('No proxy outbound found')
# Begin export
coreProtocol = Intellisense.getCoreProtocol(ob)
if coreProtocol == Protocol.VMess or coreProtocol == Protocol.VLESS:
proxyOutbound = None
outbound = getProxyOutboundObject()
for outbound in ob['outbounds']:
if outbound['tag'] == 'proxy':
proxyOutbound = outbound
break
if proxyOutbound is None:
raise Exception('No proxy outbound found')
proxyServer = proxyOutbound['settings']['vnext'][0]
def exportVMess():
proxyServer = outbound['settings']['vnext'][0]
proxyServerUser = proxyServer['users'][0]
proxyStream = proxyOutbound['streamSettings']
proxyStreamNet = proxyStream['network']
proxyStreamTLS = proxyStream['security']
proxyStream, proxyStreamNet, proxyStreamTLS = (
outbound['streamSettings'],
outbound['streamSettings']['network'],
outbound['streamSettings']['security'],
)
if coreProtocol == Protocol.VMess:
return (
'vmess://'
+ Base64Encoder.encode(
ujson.dumps(
{
'v': '2',
'ps': quote(remark),
'add': proxyServer['address'],
'port': proxyServer['port'],
'id': proxyServerUser['id'],
'aid': proxyServerUser['alterId'],
'scy': proxyServerUser['security'],
'net': proxyStreamNet,
'tls': proxyStreamTLS,
# kwargs
**getStreamNetSettings(
coreProtocol, proxyStream, proxyStreamNet
),
**getStreamTLSSettings(proxyStream, proxyStreamTLS),
},
ensure_ascii=False,
escape_forward_slashes=False,
).encode()
).decode()
)
return (
'vmess://'
+ Base64Encoder.encode(
ujson.dumps(
{
'v': '2',
'ps': quote(remark),
'add': proxyServer['address'],
'port': proxyServer['port'],
'id': proxyServerUser['id'],
'aid': proxyServerUser['alterId'],
'scy': proxyServerUser['security'],
'net': proxyStreamNet,
'tls': proxyStreamTLS,
# kwargs
**streamNetSettingsVMess(proxyStream, proxyStreamNet),
**streamTLSSettings(proxyStream, proxyStreamTLS),
},
ensure_ascii=False,
escape_forward_slashes=False,
).encode()
).decode()
)
if coreProtocol == Protocol.VLESS:
flowArg = {}
def exportVLESS():
proxyServer = outbound['settings']['vnext'][0]
proxyServerUser = proxyServer['users'][0]
if proxyServerUser.get('flow'):
flowArg['flow'] = proxyServerUser['flow']
proxyStream, proxyStreamNet, proxyStreamTLS = (
outbound['streamSettings'],
outbound['streamSettings']['network'],
outbound['streamSettings']['security'],
)
netloc = f'{proxyServerUser["id"]}@{proxyServer["address"]}:{proxyServer["port"]}'
flowArg = {}
query = '&'.join(
f'{key}={value}'
for key, value in {
'encryption': proxyServerUser['encryption'],
'type': proxyStreamNet,
'security': proxyStreamTLS,
# kwargs
**flowArg,
**getStreamNetSettings(
coreProtocol, proxyStream, proxyStreamNet
),
**getStreamTLSSettings(proxyStream, proxyStreamTLS),
}.items()
)
if proxyServerUser.get('flow'):
flowArg['flow'] = proxyServerUser['flow']
return urlunparse(['vless', netloc, '', '', query, quote(remark)])
netloc = f'{proxyServerUser["id"]}@{proxyServer["address"]}:{proxyServer["port"]}'
if coreProtocol == Protocol.Shadowsocks:
proxyOutbound = None
query = '&'.join(
f'{key}={value}'
for key, value in {
'encryption': proxyServerUser['encryption'],
'type': proxyStreamNet,
'security': proxyStreamTLS,
# kwargs
**flowArg,
**streamNetSettingsVLESS(proxyStream, proxyStreamNet),
**streamTLSSettings(proxyStream, proxyStreamTLS),
}.items()
)
for outbound in ob['outbounds']:
if outbound['tag'] == 'proxy':
proxyOutbound = outbound
return urlunparse(['vless', netloc, '', '', query, quote(remark)])
break
def exportSS():
proxyServer = outbound['settings']['servers'][0]
if proxyOutbound is None:
raise Exception('No proxy outbound found')
proxyServer = proxyOutbound['settings']['servers'][0]
method = proxyServer['method']
password = proxyServer['password']
address = proxyServer['address']
port = proxyServer['port']
method, password, address, port = (
proxyServer['method'],
proxyServer['password'],
proxyServer['address'],
proxyServer['port'],
)
netloc = f'{quote(method)}:{quote(password)}@{address}:{port}'
return urlunparse(['ss', netloc, '', '', '', quote(remark)])
else:
raise UnsupportedServerExport('Unsupported core protocol export')
def exportTrojan():
proxyServer = outbound['settings']['servers'][0]
password, address, port = (
proxyServer['password'],
proxyServer['address'],
proxyServer['port'],
)
proxyStream, proxyStreamNet, proxyStreamTLS = (
outbound['streamSettings'],
outbound['streamSettings']['network'],
outbound['streamSettings']['security'],
)
netloc = f'{quote(password)}@{address}:{port}'
query = '&'.join(
f'{key}={value}'
for key, value in {
'type': proxyStreamNet,
'security': proxyStreamTLS,
# kwargs
**streamNetSettingsVLESS(proxyStream, proxyStreamNet),
**streamTLSSettings(proxyStream, proxyStreamTLS),
}.items()
)
return urlunparse(['trojan', netloc, '', '', query, quote(remark)])
exportFuncMap = {
Protocol.VMess: exportVMess,
Protocol.VLESS: exportVLESS,
Protocol.Shadowsocks: exportSS,
Protocol.Trojan: exportTrojan,
}
return exportFuncMap[Intellisense.getCoreProtocol(ob)]()
raise UnsupportedServerExport('Unsupported core protocol export')
class OutboundObject:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def __init__(self):
super().__init__()
def build(self):
raise NotImplementedError
@@ -377,12 +461,13 @@ class ProxyOutboundObject(OutboundObject):
return TLSObject
@staticmethod
def getStreamTLSSettingsName(security):
def streamTLSKey(security):
# tlsSettings, realitySettings
return f'{security}Settings'
@staticmethod
def getStreamNetworkSettingsName(type_):
@functools.lru_cache(None)
def streamNetworkKey(type_):
if type_ == 'h2':
return 'httpSettings'
else:
@@ -483,7 +568,7 @@ class ProxyOutboundObject(OutboundObject):
'id': self.uuid_,
'security': self.encryption,
# Extension
'email': 'user@Furious.GUI',
'email': PROXY_OUTBOUND_USER_EMAIL,
}
# For VMess(V2rayN share standard) only.
@@ -497,7 +582,7 @@ class ProxyOutboundObject(OutboundObject):
'id': self.uuid_,
'encryption': self.encryption,
# Extension
'email': 'user@Furious.GUI',
'email': PROXY_OUTBOUND_USER_EMAIL,
}
if self.kwargs.get('flow'):
@@ -508,14 +593,15 @@ class ProxyOutboundObject(OutboundObject):
return {}
def build(self):
myJSON = {
def getDefaultJSON(self):
return {
'tag': 'proxy',
'protocol': self.protocol,
'settings': {
'vnext': [
{
'address': self.remote_host,
# self.remote_port is already an integer
'port': self.remote_port,
'users': [
self.getUserObject(),
@@ -533,40 +619,41 @@ class ProxyOutboundObject(OutboundObject):
},
}
def build(self):
myJSON = self.getDefaultJSON()
if self.security != 'none':
# tlsSettings, realitySettings
myJSON['streamSettings'][
ProxyOutboundObject.getStreamTLSSettingsName(self.security)
ProxyOutboundObject.streamTLSKey(self.security)
] = self.getTLSSettings(self.security)
# Stream network settings
myJSON['streamSettings'][
ProxyOutboundObject.getStreamNetworkSettingsName(self.type_)
ProxyOutboundObject.streamNetworkKey(self.type_)
] = self.getStreamNetworkSettings()
return myJSON
class ProxyOutboundObjectSS(OutboundObject):
def __init__(self, method, password, address, port, **kwargs):
super().__init__(**kwargs)
class ProxyOutboundObjectSS(ProxyOutboundObject):
def __init__(self, method, password, address, port):
super().__init__('shadowsocks', address, port, password, '', 'tcp', '')
self.method = method
self.password = password
self.address = address
self.port = int(port)
def build(self):
myJSON = {
def getDefaultJSON(self):
return {
'tag': 'proxy',
'protocol': 'shadowsocks',
'protocol': self.protocol,
'settings': {
'servers': [
{
'address': self.address,
'port': self.port,
'address': self.remote_host,
'port': int(self.remote_port),
'method': self.method,
'password': self.password,
'password': self.uuid_,
'email': PROXY_OUTBOUND_USER_EMAIL,
'ota': False,
},
]
@@ -580,7 +667,39 @@ class ProxyOutboundObjectSS(OutboundObject):
},
}
return myJSON
def build(self):
return self.getDefaultJSON()
class ProxyOutboundObjectTrojan(ProxyOutboundObject):
def __init__(self, password, address, port, type_, security, **kwargs):
super().__init__(
'trojan', address, port, password, '', type_, security, **kwargs
)
def getDefaultJSON(self):
return {
'tag': 'proxy',
'protocol': self.protocol,
'settings': {
'servers': [
{
'address': self.remote_host,
'port': int(self.remote_port),
'password': self.uuid_,
'email': PROXY_OUTBOUND_USER_EMAIL,
},
]
},
'streamSettings': {
'network': self.type_,
'security': self.security,
},
'mux': {
'enabled': False,
'concurrency': -1,
},
}
class Outbounds:
+22 -6
View File
@@ -70,6 +70,8 @@ class Intellisense:
if outbound['tag'] == 'proxy':
return protocolRepr(outbound['protocol'])
return ''
if Intellisense.getCoreType(ob) == Hysteria1.name():
return Protocol.Hysteria1
@@ -86,10 +88,10 @@ class Intellisense:
def getCoreAddr(ob):
try:
if Intellisense.getCoreType(ob) == XrayCore.name():
protocol = Intellisense.getCoreProtocol(ob)
for outbound in ob['outbounds']:
if outbound['tag'] == 'proxy':
protocol = protocolRepr(outbound['protocol'])
if protocol == Protocol.VMess or protocol == Protocol.VLESS:
return ';'.join(
list(
@@ -98,7 +100,10 @@ class Intellisense:
)
)
if protocol == Protocol.Shadowsocks:
if (
protocol == Protocol.Shadowsocks
or protocol == Protocol.Trojan
):
return ';'.join(
list(
f'{server["address"]}'
@@ -106,6 +111,8 @@ class Intellisense:
)
)
return ''
if Intellisense.getCoreType(ob) == Hysteria1.name():
return ob['server'].split(':')[0]
@@ -122,10 +129,10 @@ class Intellisense:
def getCorePort(ob):
try:
if Intellisense.getCoreType(ob) == XrayCore.name():
protocol = Intellisense.getCoreProtocol(ob)
for outbound in ob['outbounds']:
if outbound['tag'] == 'proxy':
protocol = protocolRepr(outbound['protocol'])
if protocol == Protocol.VMess or protocol == Protocol.VLESS:
return ';'.join(
list(
@@ -134,7 +141,10 @@ class Intellisense:
)
)
if protocol == Protocol.Shadowsocks:
if (
protocol == Protocol.Shadowsocks
or protocol == Protocol.Trojan
):
return ';'.join(
list(
f'{server["port"]}'
@@ -142,6 +152,8 @@ class Intellisense:
)
)
return ''
if Intellisense.getCoreType(ob) == Hysteria1.name():
return ob['server'].split(':')[1]
@@ -162,6 +174,8 @@ class Intellisense:
if outbound['tag'] == 'proxy':
return outbound['streamSettings']['network']
return ''
return ''
except Exception:
# Any non-exit exceptions
@@ -176,6 +190,8 @@ class Intellisense:
if outbound['tag'] == 'proxy':
return outbound['streamSettings']['security']
return ''
return ''
except Exception:
# Any non-exit exceptions
+2
View File
@@ -37,6 +37,8 @@ APPLICATION_REPO_NAME = 'Furious'
ORGANIZATION_NAME = 'Furious'
ORGANIZATION_DOMAIN = 'Furious.GUI'
PROXY_OUTBOUND_USER_EMAIL = f'user@{ORGANIZATION_DOMAIN}'
PLATFORM = platform.system()
LOCAL_SERVER_NAME = '891ad49d-8996-43cb-820c-d9baf42a04de'
+9 -1
View File
@@ -45,10 +45,12 @@ logger = logging.getLogger(__name__)
class Base64Encoder:
@staticmethod
@functools.lru_cache(32)
def encode(text):
return pybase64.b64encode(text)
@staticmethod
@functools.lru_cache(32)
def decode(text):
return pybase64.b64decode(text, validate=False)
@@ -56,7 +58,8 @@ class Base64Encoder:
class Protocol:
VMess = 'VMess'
VLESS = 'VLESS'
Shadowsocks = 'shadowsocks'
Shadowsocks = 'Shadowsocks'
Trojan = 'Trojan'
Hysteria1 = 'hysteria1'
Hysteria2 = 'hysteria2'
@@ -226,6 +229,7 @@ class AsyncSubprocessMessage:
return self.msgQueue.get_nowait()
except queue.Empty:
# Queue is empty
return ''
@@ -328,9 +332,13 @@ def protocolRepr(protocol):
if protocol.lower() == 'shadowsocks':
return Protocol.Shadowsocks
if protocol.lower() == 'trojan':
return Protocol.Trojan
return protocol
@functools.lru_cache(None)
def isValidIPAddress(address):
try:
ipaddress.ip_address(address)