Add local-proxy loopback enforcement setting

Signed-off-by: Loren Eteval <loren.eteval@proton.me>
This commit is contained in:
Loren Eteval
2026-01-03 23:52:34 +08:00
parent 0772b71c32
commit 01b0e516ba
6 changed files with 77 additions and 5 deletions
+8
View File
@@ -1091,6 +1091,14 @@ TRANSLATION = {
"ZH": "开机启动",
"isReviewed": "True"
},
"Force To 127.0.0.1 When Setting Local Proxy": {
"source": [
"Furious.TrayActions.Settings"
],
"RU": "Принудительно 127.0.0.1 для локального прокси",
"ZH": "设置本地代理时强制使用127.0.0.1",
"isReviewed": "True"
},
"Automatically Update Asset Files": {
"source": [
"Furious.TrayActions.Settings"
+5
View File
@@ -82,6 +82,11 @@ class SystemRuntime:
else:
return ''
@staticmethod
@functools.lru_cache(None)
def isAssetsFolderWritable() -> bool:
return os.access(XRAY_ASSET_DIR, os.W_OK)
@staticmethod
@functools.lru_cache(None)
def isAdmin() -> bool:
+31
View File
@@ -18,6 +18,7 @@
from __future__ import annotations
from Furious.Frozenlib.Constants import *
from Furious.Frozenlib.AppSettings import *
from enum import Enum
from typing import AnyStr, Tuple
@@ -34,6 +35,7 @@ import urllib.parse
__all__ = [
'Protocol',
'callRateLimited',
'forceToLocalhostIfPossible',
'callOnceOnly',
'classname',
'isValidIPAddress',
@@ -82,6 +84,7 @@ def callRateLimited(maxCallPerSecond):
called = time.monotonic()
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
# Previously called
nonlocal called
@@ -102,6 +105,34 @@ def callRateLimited(maxCallPerSecond):
return decorator
def forceToLocalhostIfPossible():
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
if (
AppSettings.isStateOFF('ForceToLocalhostWhenSettingLocalProxy')
or not isinstance(result, str)
or result == ''
):
return result
# Force to localhost according to settings
try:
host, port = parseHostPort(result)
return f'127.0.0.1:{port}'
except Exception:
# Any non-exit exceptions
return result
return wrapper
return decorator
def callOnceOnly(func):
"""
Decorator that ensures a function is only called once.
+1
View File
@@ -63,6 +63,7 @@ class Storage:
class Extras:
@staticmethod
@forceToLocalhostIfPossible()
def UserHttpProxy() -> Union[str, None]:
try:
if APP().isSystemTrayConnected():
+12 -4
View File
@@ -210,7 +210,13 @@ class ConnectAction(AppQAction):
else:
assert isinstance(config, ConfigFactory)
if not validateProxyServer(config.httpProxy()):
@forceToLocalhostIfPossible()
def getHttpProxy() -> str:
return config.httpProxy()
httpProxy = getHttpProxy()
if not validateProxyServer(httpProxy):
# Proxy server is not valid. Do not connect
AppSettings.turnOFF('Connect')
@@ -247,7 +253,7 @@ class ConnectAction(AppQAction):
if self.actionQueue.empty():
if success:
SystemProxy.set(config.httpProxy(), PROXY_SERVER_BYPASS)
SystemProxy.set(httpProxy, PROXY_SERVER_BYPASS)
self.doConnected()
@@ -291,11 +297,13 @@ class ConnectAction(AppQAction):
hasNewVersionCallback=newVersionCallback,
)
if SystemRuntime.appImagePath() or SystemRuntime.flatpakID():
if not SystemRuntime.isAssetsFolderWritable():
logger.info(
'skipped auto assets update due to application folder not writable'
f'skipped auto assets update due to assets folder \'{XRAY_ASSET_DIR}\' not writable'
)
else:
logger.info(f'assets folder \'{XRAY_ASSET_DIR}\' is writable. Continue')
if AppSettings.isStateON_('AutoUpdateAssetFiles'):
# Automatically update assets
self.assetDownloadManager.configureHttpProxy(connectedHttpProxy)
+20 -1
View File
@@ -32,6 +32,11 @@ if PLATFORM == 'Darwin':
registerAppSettings('StartupOnBoot', isBinary=True, default=AppBinarySettings.ON_)
registerAppSettings('PowerSaveMode', isBinary=True, default=AppBinarySettings.ON_)
registerAppSettings(
'ForceToLocalhostWhenSettingLocalProxy',
isBinary=True,
default=AppBinarySettings.OFF,
)
registerAppSettings(
'AutoUpdateAssetFiles', isBinary=True, default=AppBinarySettings.ON_
)
@@ -135,6 +140,13 @@ class SettingsChildAction(AppQAction):
else:
AppSettings.turnOFF('PowerSaveMode')
showMBoxNewChangesNextTime()
elif self.textCompare('Force To 127.0.0.1 When Setting Local Proxy'):
if checked:
AppSettings.turnON_('ForceToLocalhostWhenSettingLocalProxy')
else:
AppSettings.turnOFF('ForceToLocalhostWhenSettingLocalProxy')
showMBoxNewChangesNextTime()
elif self.textCompare('Automatically Update Asset Files'):
if checked:
@@ -187,7 +199,7 @@ class SettingsAction(AppQAction):
else:
hideDockIconAction = []
if SystemRuntime.appImagePath() or SystemRuntime.flatpakID():
if not SystemRuntime.isAssetsFolderWritable():
autoUpdateAssetFilesAction = []
else:
autoUpdateAssetFilesAction = (
@@ -226,6 +238,13 @@ class SettingsAction(AppQAction):
checked=AppSettings.isStateON_('PowerSaveMode'),
),
AppQSeperator(),
SettingsChildAction(
_('Force To 127.0.0.1 When Setting Local Proxy'),
checkable=True,
checked=AppSettings.isStateON_(
'ForceToLocalhostWhenSettingLocalProxy'
),
),
*autoUpdateAssetFilesAction,
SettingsChildAction(
_('Show Progress Bar When Connecting'),