421 lines
20 KiB
Python
421 lines
20 KiB
Python
from __future__ import annotations
|
|
|
|
from PySide6.QtCore import QSize
|
|
from PySide6.QtWidgets import (
|
|
QApplication,
|
|
QCheckBox,
|
|
QComboBox,
|
|
QFormLayout,
|
|
QGroupBox,
|
|
QHBoxLayout,
|
|
QLabel,
|
|
QLineEdit,
|
|
QPushButton,
|
|
QRadioButton,
|
|
QSpinBox,
|
|
QToolButton,
|
|
QVBoxLayout,
|
|
QWidget,
|
|
)
|
|
|
|
from main_window.constants import SINGBOX_EDITOR_PROTOCOL_IDS, SINGBOX_EDITOR_PROTOCOL_OPTIONS
|
|
|
|
|
|
class UITabsSingBoxEditorMixin:
|
|
def _build_singbox_vless_editor(self, parent_layout: QVBoxLayout) -> None:
|
|
grp = QGroupBox("Protocol editor (client)")
|
|
self.grp_singbox_proto_editor = grp
|
|
lay = QVBoxLayout(grp)
|
|
|
|
self.lbl_singbox_proto_editor_info = QLabel(
|
|
"Client-side fields only. Server billing/traffic/expiry fields are excluded."
|
|
)
|
|
self.lbl_singbox_proto_editor_info.setStyleSheet("color: gray;")
|
|
lay.addWidget(self.lbl_singbox_proto_editor_info)
|
|
|
|
form = QFormLayout()
|
|
self.frm_singbox_proto_form = form
|
|
|
|
self.ent_singbox_proto_name = QLineEdit()
|
|
self.ent_singbox_proto_name.setPlaceholderText("Profile name")
|
|
form.addRow("Profile name:", self.ent_singbox_proto_name)
|
|
|
|
self.chk_singbox_proto_enabled = QCheckBox("Enabled")
|
|
self.chk_singbox_proto_enabled.setChecked(True)
|
|
form.addRow("Enabled:", self.chk_singbox_proto_enabled)
|
|
|
|
self.cmb_singbox_proto_protocol = QComboBox()
|
|
for label, pid in SINGBOX_EDITOR_PROTOCOL_OPTIONS:
|
|
self.cmb_singbox_proto_protocol.addItem(label, pid)
|
|
self.cmb_singbox_proto_protocol.currentIndexChanged.connect(
|
|
self.on_singbox_vless_editor_changed
|
|
)
|
|
form.addRow("Protocol:", self.cmb_singbox_proto_protocol)
|
|
|
|
self.ent_singbox_vless_server = QLineEdit()
|
|
self.ent_singbox_vless_server.setPlaceholderText("example.com")
|
|
form.addRow("Address:", self.ent_singbox_vless_server)
|
|
|
|
self.spn_singbox_vless_port = QSpinBox()
|
|
self.spn_singbox_vless_port.setRange(1, 65535)
|
|
self.spn_singbox_vless_port.setValue(443)
|
|
form.addRow("Port:", self.spn_singbox_vless_port)
|
|
|
|
self.ent_singbox_vless_uuid = QLineEdit()
|
|
self.ent_singbox_vless_uuid.setPlaceholderText("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
|
|
form.addRow("UUID:", self.ent_singbox_vless_uuid)
|
|
|
|
self.ent_singbox_proto_password = QLineEdit()
|
|
self.ent_singbox_proto_password.setPlaceholderText("password")
|
|
form.addRow("Password:", self.ent_singbox_proto_password)
|
|
|
|
self.cmb_singbox_vless_flow = QComboBox()
|
|
self.cmb_singbox_vless_flow.addItem("None", "")
|
|
# sing-box v1.12/v1.13 VLESS flow preset; field remains editable for custom/raw values.
|
|
self.cmb_singbox_vless_flow.addItem("xtls-rprx-vision", "xtls-rprx-vision")
|
|
self.cmb_singbox_vless_flow.setEditable(True)
|
|
self.cmb_singbox_vless_flow.setInsertPolicy(QComboBox.NoInsert)
|
|
form.addRow("Flow:", self.cmb_singbox_vless_flow)
|
|
|
|
self.cmb_singbox_vless_packet_encoding = QComboBox()
|
|
self.cmb_singbox_vless_packet_encoding.addItem("auto", "")
|
|
self.cmb_singbox_vless_packet_encoding.addItem("xudp", "xudp")
|
|
form.addRow("Packet encoding:", self.cmb_singbox_vless_packet_encoding)
|
|
|
|
self.cmb_singbox_ss_method = QComboBox()
|
|
self.cmb_singbox_ss_method.setEditable(True)
|
|
self.cmb_singbox_ss_method.setInsertPolicy(QComboBox.NoInsert)
|
|
for method in (
|
|
"aes-128-gcm",
|
|
"aes-256-gcm",
|
|
"chacha20-ietf-poly1305",
|
|
"2022-blake3-aes-128-gcm",
|
|
"2022-blake3-aes-256-gcm",
|
|
"none",
|
|
):
|
|
self.cmb_singbox_ss_method.addItem(method, method)
|
|
form.addRow("SS method:", self.cmb_singbox_ss_method)
|
|
|
|
self.ent_singbox_ss_plugin = QLineEdit()
|
|
self.ent_singbox_ss_plugin.setPlaceholderText("obfs-local;obfs=http;obfs-host=example.com")
|
|
form.addRow("SS plugin:", self.ent_singbox_ss_plugin)
|
|
|
|
self.spn_singbox_hy2_up_mbps = QSpinBox()
|
|
self.spn_singbox_hy2_up_mbps.setRange(0, 100000)
|
|
form.addRow("HY2 up mbps:", self.spn_singbox_hy2_up_mbps)
|
|
|
|
self.spn_singbox_hy2_down_mbps = QSpinBox()
|
|
self.spn_singbox_hy2_down_mbps.setRange(0, 100000)
|
|
form.addRow("HY2 down mbps:", self.spn_singbox_hy2_down_mbps)
|
|
|
|
self.ent_singbox_hy2_obfs = QLineEdit()
|
|
self.ent_singbox_hy2_obfs.setPlaceholderText("salamander")
|
|
form.addRow("HY2 obfs type:", self.ent_singbox_hy2_obfs)
|
|
|
|
self.ent_singbox_hy2_obfs_password = QLineEdit()
|
|
self.ent_singbox_hy2_obfs_password.setPlaceholderText("obfs password")
|
|
form.addRow("HY2 obfs password:", self.ent_singbox_hy2_obfs_password)
|
|
|
|
self.cmb_singbox_tuic_congestion = QComboBox()
|
|
self.cmb_singbox_tuic_congestion.setEditable(True)
|
|
self.cmb_singbox_tuic_congestion.setInsertPolicy(QComboBox.NoInsert)
|
|
self.cmb_singbox_tuic_congestion.addItem("Default", "")
|
|
self.cmb_singbox_tuic_congestion.addItem("bbr", "bbr")
|
|
self.cmb_singbox_tuic_congestion.addItem("cubic", "cubic")
|
|
self.cmb_singbox_tuic_congestion.addItem("new_reno", "new_reno")
|
|
form.addRow("TUIC congestion:", self.cmb_singbox_tuic_congestion)
|
|
|
|
self.cmb_singbox_tuic_udp_mode = QComboBox()
|
|
self.cmb_singbox_tuic_udp_mode.addItem("Default", "")
|
|
self.cmb_singbox_tuic_udp_mode.addItem("native", "native")
|
|
self.cmb_singbox_tuic_udp_mode.addItem("quic", "quic")
|
|
form.addRow("TUIC UDP relay:", self.cmb_singbox_tuic_udp_mode)
|
|
|
|
self.chk_singbox_tuic_zero_rtt = QCheckBox("Enable zero RTT handshake")
|
|
form.addRow("TUIC zero RTT:", self.chk_singbox_tuic_zero_rtt)
|
|
|
|
self.ent_singbox_wg_private_key = QLineEdit()
|
|
self.ent_singbox_wg_private_key.setPlaceholderText("wireguard private key")
|
|
self.ent_singbox_wg_private_key.setEchoMode(QLineEdit.PasswordEchoOnEdit)
|
|
form.addRow("WG private key:", self.ent_singbox_wg_private_key)
|
|
|
|
self.ent_singbox_wg_peer_public_key = QLineEdit()
|
|
self.ent_singbox_wg_peer_public_key.setPlaceholderText("peer public key")
|
|
self.ent_singbox_wg_peer_public_key.setEchoMode(QLineEdit.PasswordEchoOnEdit)
|
|
form.addRow("WG peer public key:", self.ent_singbox_wg_peer_public_key)
|
|
|
|
self.ent_singbox_wg_psk = QLineEdit()
|
|
self.ent_singbox_wg_psk.setPlaceholderText("pre-shared key (optional)")
|
|
self.ent_singbox_wg_psk.setEchoMode(QLineEdit.PasswordEchoOnEdit)
|
|
form.addRow("WG pre-shared key:", self.ent_singbox_wg_psk)
|
|
|
|
self.ent_singbox_wg_local_address = QLineEdit()
|
|
self.ent_singbox_wg_local_address.setPlaceholderText("10.0.0.2/32,fd00::2/128")
|
|
form.addRow("WG local address:", self.ent_singbox_wg_local_address)
|
|
|
|
self.ent_singbox_wg_reserved = QLineEdit()
|
|
self.ent_singbox_wg_reserved.setPlaceholderText("0,0,0 (optional)")
|
|
form.addRow("WG reserved:", self.ent_singbox_wg_reserved)
|
|
|
|
self.spn_singbox_wg_mtu = QSpinBox()
|
|
self.spn_singbox_wg_mtu.setRange(0, 9200)
|
|
form.addRow("WG MTU:", self.spn_singbox_wg_mtu)
|
|
|
|
self.cmb_singbox_vless_transport = QComboBox()
|
|
self.cmb_singbox_vless_transport.addItem("TCP (RAW)", "tcp")
|
|
self.cmb_singbox_vless_transport.addItem("WebSocket", "ws")
|
|
self.cmb_singbox_vless_transport.addItem("gRPC", "grpc")
|
|
self.cmb_singbox_vless_transport.addItem("HTTP", "http")
|
|
self.cmb_singbox_vless_transport.addItem("HTTP Upgrade", "httpupgrade")
|
|
self.cmb_singbox_vless_transport.addItem("QUIC", "quic")
|
|
self.cmb_singbox_vless_transport.currentIndexChanged.connect(
|
|
self.on_singbox_vless_editor_changed
|
|
)
|
|
form.addRow("Transport:", self.cmb_singbox_vless_transport)
|
|
|
|
self.ent_singbox_vless_path = QLineEdit()
|
|
self.ent_singbox_vless_path.setPlaceholderText("/")
|
|
form.addRow("Transport path:", self.ent_singbox_vless_path)
|
|
|
|
self.ent_singbox_vless_grpc_service = QLineEdit()
|
|
self.ent_singbox_vless_grpc_service.setPlaceholderText("service-name")
|
|
form.addRow("gRPC service:", self.ent_singbox_vless_grpc_service)
|
|
|
|
self.cmb_singbox_vless_security = QComboBox()
|
|
self.cmb_singbox_vless_security.addItem("None", "none")
|
|
self.cmb_singbox_vless_security.addItem("TLS", "tls")
|
|
self.cmb_singbox_vless_security.addItem("Reality", "reality")
|
|
self.cmb_singbox_vless_security.currentIndexChanged.connect(
|
|
self.on_singbox_vless_editor_changed
|
|
)
|
|
form.addRow("Security:", self.cmb_singbox_vless_security)
|
|
|
|
self.ent_singbox_vless_sni = QLineEdit()
|
|
self.ent_singbox_vless_sni.setPlaceholderText("www.example.com")
|
|
form.addRow("SNI:", self.ent_singbox_vless_sni)
|
|
|
|
self.ent_singbox_tls_alpn = QLineEdit()
|
|
self.ent_singbox_tls_alpn.setPlaceholderText("h2,http/1.1")
|
|
form.addRow("TLS ALPN:", self.ent_singbox_tls_alpn)
|
|
|
|
self.cmb_singbox_vless_utls_fp = QComboBox()
|
|
self.cmb_singbox_vless_utls_fp.addItem("Default", "")
|
|
self.cmb_singbox_vless_utls_fp.addItem("chrome", "chrome")
|
|
self.cmb_singbox_vless_utls_fp.addItem("firefox", "firefox")
|
|
self.cmb_singbox_vless_utls_fp.addItem("safari", "safari")
|
|
self.cmb_singbox_vless_utls_fp.addItem("edge", "edge")
|
|
form.addRow("uTLS fingerprint:", self.cmb_singbox_vless_utls_fp)
|
|
|
|
self.ent_singbox_vless_reality_pk = QLineEdit()
|
|
self.ent_singbox_vless_reality_pk.setPlaceholderText("Reality public key")
|
|
form.addRow("Reality public key:", self.ent_singbox_vless_reality_pk)
|
|
|
|
self.ent_singbox_vless_reality_sid = QLineEdit()
|
|
self.ent_singbox_vless_reality_sid.setPlaceholderText("short_id")
|
|
form.addRow("Reality short id:", self.ent_singbox_vless_reality_sid)
|
|
|
|
self.chk_singbox_vless_insecure = QCheckBox("Allow insecure TLS")
|
|
form.addRow("TLS insecure:", self.chk_singbox_vless_insecure)
|
|
|
|
self.chk_singbox_vless_sniff = QCheckBox("Enable sniffing for local inbound")
|
|
self.chk_singbox_vless_sniff.setChecked(True)
|
|
form.addRow("Sniffing:", self.chk_singbox_vless_sniff)
|
|
|
|
lay.addLayout(form)
|
|
|
|
wg_helpers = QHBoxLayout()
|
|
self.btn_singbox_wg_paste_private = QToolButton()
|
|
self.btn_singbox_wg_paste_private.setText("Paste private")
|
|
self.btn_singbox_wg_paste_private.clicked.connect(
|
|
lambda: self._paste_line_edit_from_clipboard(self.ent_singbox_wg_private_key)
|
|
)
|
|
wg_helpers.addWidget(self.btn_singbox_wg_paste_private)
|
|
|
|
self.btn_singbox_wg_copy_private = QToolButton()
|
|
self.btn_singbox_wg_copy_private.setText("Copy private")
|
|
self.btn_singbox_wg_copy_private.clicked.connect(
|
|
lambda: self._copy_line_edit_to_clipboard(self.ent_singbox_wg_private_key)
|
|
)
|
|
wg_helpers.addWidget(self.btn_singbox_wg_copy_private)
|
|
|
|
self.btn_singbox_wg_paste_peer = QToolButton()
|
|
self.btn_singbox_wg_paste_peer.setText("Paste peer")
|
|
self.btn_singbox_wg_paste_peer.clicked.connect(
|
|
lambda: self._paste_line_edit_from_clipboard(self.ent_singbox_wg_peer_public_key)
|
|
)
|
|
wg_helpers.addWidget(self.btn_singbox_wg_paste_peer)
|
|
|
|
self.btn_singbox_wg_copy_peer = QToolButton()
|
|
self.btn_singbox_wg_copy_peer.setText("Copy peer")
|
|
self.btn_singbox_wg_copy_peer.clicked.connect(
|
|
lambda: self._copy_line_edit_to_clipboard(self.ent_singbox_wg_peer_public_key)
|
|
)
|
|
wg_helpers.addWidget(self.btn_singbox_wg_copy_peer)
|
|
|
|
self.btn_singbox_wg_paste_psk = QToolButton()
|
|
self.btn_singbox_wg_paste_psk.setText("Paste PSK")
|
|
self.btn_singbox_wg_paste_psk.clicked.connect(
|
|
lambda: self._paste_line_edit_from_clipboard(self.ent_singbox_wg_psk)
|
|
)
|
|
wg_helpers.addWidget(self.btn_singbox_wg_paste_psk)
|
|
|
|
self.btn_singbox_wg_copy_psk = QToolButton()
|
|
self.btn_singbox_wg_copy_psk.setText("Copy PSK")
|
|
self.btn_singbox_wg_copy_psk.clicked.connect(
|
|
lambda: self._copy_line_edit_to_clipboard(self.ent_singbox_wg_psk)
|
|
)
|
|
wg_helpers.addWidget(self.btn_singbox_wg_copy_psk)
|
|
wg_helpers.addStretch(1)
|
|
|
|
self.wdg_singbox_wg_key_helpers = QWidget()
|
|
self.wdg_singbox_wg_key_helpers.setLayout(wg_helpers)
|
|
lay.addWidget(self.wdg_singbox_wg_key_helpers)
|
|
|
|
self.lbl_singbox_proto_guardrails = QLabel("Guardrails: address/port/uuid required")
|
|
self.lbl_singbox_proto_guardrails.setStyleSheet("color: gray;")
|
|
lay.addWidget(self.lbl_singbox_proto_guardrails)
|
|
|
|
parent_layout.addWidget(grp)
|
|
|
|
self.on_singbox_vless_editor_changed()
|
|
|
|
def _set_proto_form_row_visible(self, field: QWidget, visible: bool) -> None:
|
|
field.setVisible(visible)
|
|
label = None
|
|
form = getattr(self, "frm_singbox_proto_form", None)
|
|
if form is not None:
|
|
try:
|
|
label = form.labelForField(field)
|
|
except Exception:
|
|
label = None
|
|
if label is not None:
|
|
label.setVisible(visible)
|
|
|
|
def _copy_line_edit_to_clipboard(self, field: QLineEdit) -> None:
|
|
txt = str(field.text() or "").strip()
|
|
if txt:
|
|
QApplication.clipboard().setText(txt)
|
|
|
|
def _paste_line_edit_from_clipboard(self, field: QLineEdit) -> None:
|
|
txt = str(QApplication.clipboard().text() or "").strip()
|
|
field.setText(txt)
|
|
|
|
def _current_editor_protocol(self) -> str:
|
|
return str(self.cmb_singbox_proto_protocol.currentData() or "vless").strip().lower() or "vless"
|
|
|
|
def _is_supported_editor_protocol(self, protocol: str) -> bool:
|
|
return str(protocol or "").strip().lower() in SINGBOX_EDITOR_PROTOCOL_IDS
|
|
|
|
def on_singbox_vless_editor_changed(self, _index: int = 0) -> None:
|
|
protocol = self._current_editor_protocol()
|
|
self._singbox_editor_protocol = protocol
|
|
|
|
transport = str(self.cmb_singbox_vless_transport.currentData() or "tcp").strip().lower()
|
|
security = str(self.cmb_singbox_vless_security.currentData() or "none").strip().lower()
|
|
if protocol == "vless":
|
|
self.cmb_singbox_vless_security.setEnabled(True)
|
|
elif protocol == "trojan":
|
|
if security == "reality":
|
|
idx = self.cmb_singbox_vless_security.findData("tls")
|
|
self.cmb_singbox_vless_security.setCurrentIndex(idx if idx >= 0 else 1)
|
|
security = "tls"
|
|
self.cmb_singbox_vless_security.setEnabled(True)
|
|
elif protocol in ("hysteria2", "tuic"):
|
|
idx = self.cmb_singbox_vless_security.findData("tls")
|
|
self.cmb_singbox_vless_security.setCurrentIndex(idx if idx >= 0 else 1)
|
|
security = "tls"
|
|
self.cmb_singbox_vless_security.setEnabled(False)
|
|
elif protocol == "wireguard":
|
|
idx = self.cmb_singbox_vless_security.findData("none")
|
|
self.cmb_singbox_vless_security.setCurrentIndex(idx if idx >= 0 else 0)
|
|
security = "none"
|
|
self.cmb_singbox_vless_security.setEnabled(False)
|
|
else:
|
|
idx = self.cmb_singbox_vless_security.findData("none")
|
|
self.cmb_singbox_vless_security.setCurrentIndex(idx if idx >= 0 else 0)
|
|
security = "none"
|
|
self.cmb_singbox_vless_security.setEnabled(False)
|
|
|
|
path_needed = transport in ("ws", "http", "httpupgrade")
|
|
grpc_needed = transport == "grpc"
|
|
transport_supported = protocol in ("vless", "trojan")
|
|
|
|
self.cmb_singbox_vless_transport.setEnabled(transport_supported)
|
|
self.ent_singbox_vless_path.setEnabled(transport_supported and path_needed)
|
|
self.ent_singbox_vless_grpc_service.setEnabled(transport_supported and grpc_needed)
|
|
|
|
tls_like = security in ("tls", "reality")
|
|
reality = security == "reality"
|
|
|
|
self.ent_singbox_vless_sni.setEnabled(tls_like)
|
|
self.ent_singbox_tls_alpn.setEnabled(tls_like)
|
|
self.cmb_singbox_vless_utls_fp.setEnabled(tls_like)
|
|
self.chk_singbox_vless_insecure.setEnabled(tls_like)
|
|
self.ent_singbox_vless_reality_pk.setEnabled(reality)
|
|
self.ent_singbox_vless_reality_sid.setEnabled(reality)
|
|
|
|
show_vless_auth = protocol == "vless"
|
|
show_password = protocol in ("trojan", "shadowsocks", "hysteria2", "tuic")
|
|
show_ss = protocol == "shadowsocks"
|
|
show_hy2 = protocol == "hysteria2"
|
|
show_tuic = protocol == "tuic"
|
|
show_wg = protocol == "wireguard"
|
|
|
|
self._set_proto_form_row_visible(self.ent_singbox_vless_uuid, show_vless_auth or show_tuic)
|
|
self._set_proto_form_row_visible(self.ent_singbox_proto_password, show_password)
|
|
self._set_proto_form_row_visible(self.cmb_singbox_vless_flow, show_vless_auth)
|
|
self._set_proto_form_row_visible(self.cmb_singbox_vless_packet_encoding, show_vless_auth)
|
|
|
|
self._set_proto_form_row_visible(self.cmb_singbox_ss_method, show_ss)
|
|
self._set_proto_form_row_visible(self.ent_singbox_ss_plugin, show_ss)
|
|
|
|
self._set_proto_form_row_visible(self.spn_singbox_hy2_up_mbps, show_hy2)
|
|
self._set_proto_form_row_visible(self.spn_singbox_hy2_down_mbps, show_hy2)
|
|
self._set_proto_form_row_visible(self.ent_singbox_hy2_obfs, show_hy2)
|
|
self._set_proto_form_row_visible(self.ent_singbox_hy2_obfs_password, show_hy2)
|
|
|
|
self._set_proto_form_row_visible(self.cmb_singbox_tuic_congestion, show_tuic)
|
|
self._set_proto_form_row_visible(self.cmb_singbox_tuic_udp_mode, show_tuic)
|
|
self._set_proto_form_row_visible(self.chk_singbox_tuic_zero_rtt, show_tuic)
|
|
|
|
self._set_proto_form_row_visible(self.ent_singbox_wg_private_key, show_wg)
|
|
self._set_proto_form_row_visible(self.ent_singbox_wg_peer_public_key, show_wg)
|
|
self._set_proto_form_row_visible(self.ent_singbox_wg_psk, show_wg)
|
|
self._set_proto_form_row_visible(self.ent_singbox_wg_local_address, show_wg)
|
|
self._set_proto_form_row_visible(self.ent_singbox_wg_reserved, show_wg)
|
|
self._set_proto_form_row_visible(self.spn_singbox_wg_mtu, show_wg)
|
|
self.wdg_singbox_wg_key_helpers.setVisible(show_wg)
|
|
|
|
self._set_proto_form_row_visible(self.cmb_singbox_vless_transport, transport_supported)
|
|
self._set_proto_form_row_visible(self.ent_singbox_vless_path, transport_supported)
|
|
self._set_proto_form_row_visible(self.ent_singbox_vless_grpc_service, transport_supported)
|
|
|
|
self._set_proto_form_row_visible(self.cmb_singbox_vless_security, protocol not in ("shadowsocks", "wireguard"))
|
|
self._set_proto_form_row_visible(self.ent_singbox_vless_sni, tls_like)
|
|
self._set_proto_form_row_visible(self.ent_singbox_tls_alpn, tls_like)
|
|
self._set_proto_form_row_visible(self.cmb_singbox_vless_utls_fp, tls_like)
|
|
self._set_proto_form_row_visible(self.chk_singbox_vless_insecure, tls_like)
|
|
self._set_proto_form_row_visible(self.ent_singbox_vless_reality_pk, reality)
|
|
self._set_proto_form_row_visible(self.ent_singbox_vless_reality_sid, reality)
|
|
|
|
tips = ["Guardrails:"]
|
|
if protocol == "vless":
|
|
tips.append("address/port/uuid required")
|
|
elif protocol == "trojan":
|
|
tips.append("address/port/password required")
|
|
elif protocol == "shadowsocks":
|
|
tips.append("address/port/SS method/password required")
|
|
elif protocol == "hysteria2":
|
|
tips.append("address/port/password required")
|
|
elif protocol == "tuic":
|
|
tips.append("address/port/uuid/password required")
|
|
elif protocol == "wireguard":
|
|
tips.append("address/port/private_key/peer_public_key/local_address required")
|
|
if reality:
|
|
tips.append("reality.public_key is required")
|
|
if transport_supported and grpc_needed:
|
|
tips.append("gRPC service is required")
|
|
if transport_supported and path_needed:
|
|
tips.append("transport path is required")
|
|
self.lbl_singbox_proto_guardrails.setText(" | ".join(tips))
|