Skip to content

Commit f1e1430

Browse files
misakano7545claude
andcommitted
fix(common,agent): unify frame size limit, quote YAML special chars, lock config removal in disable_restrictions
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent c9757f3 commit f1e1430

5 files changed

Lines changed: 49 additions & 14 deletions

File tree

.github/workflows/build-windows.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
- name: win7
2020
python-version: "3.8"
2121
- name: win10
22-
python-version: "3.11"
22+
python-version: "3.13"
2323

2424
steps:
2525
- name: Checkout

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,7 @@ configs/config.yaml
1818
agent/configs
1919

2020
# Trae
21-
.trae/
21+
.trae/
22+
23+
# Pycharm
24+
.idea/

agent/firewall_manager.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -308,9 +308,20 @@ def disable_restrictions() -> Tuple[bool, str]:
308308
if not is_admin():
309309
return False, "需要管理员权限"
310310

311-
_stop_clash_process()
312-
if os.path.exists(CLASH_CONFIG_FILE):
313-
os.remove(CLASH_CONFIG_FILE)
311+
with CLASH_PROCESS_LOCK:
312+
global _clash_process
313+
if _clash_process is not None:
314+
try:
315+
_clash_process.terminate()
316+
_clash_process.wait(timeout=5)
317+
except Exception:
318+
try:
319+
_clash_process.kill()
320+
except Exception:
321+
pass
322+
_clash_process = None
323+
if os.path.exists(CLASH_CONFIG_FILE):
324+
os.remove(CLASH_CONFIG_FILE)
314325

315326
return True, "已解除网络限制"
316327

common/clash_config.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,29 @@ def build_clash_config(mode: str, rules: List[Dict[str, str]]) -> Dict[str, Any]
121121
return config
122122

123123

124+
def _yaml_quote(s: str) -> str:
125+
"""Quote a string value if it contains YAML-special characters."""
126+
if not s:
127+
return "''"
128+
needs_quote = (
129+
s.startswith(("{", "[", "'", '"', "*", "&", "!", "|", ">", "%", "@", "`"))
130+
or "#" in s
131+
or ": " in s
132+
or s.endswith(":")
133+
or s.startswith("- ")
134+
or s.strip() != s
135+
or s.lower() in ("true", "false", "null", "yes", "no", "on", "off")
136+
)
137+
if not needs_quote:
138+
return s
139+
escaped = s.replace("'", "''")
140+
return f"'{escaped}'"
141+
142+
124143
def config_to_yaml(config: Dict[str, Any]) -> str:
125144
"""Convert config dict to YAML string."""
126145
lines = []
127-
146+
128147
def add_line(key: str, value, indent: int = 0):
129148
prefix = " " * indent
130149
if isinstance(value, dict):
@@ -139,15 +158,15 @@ def add_line(key: str, value, indent: int = 0):
139158
for k, v in item.items():
140159
add_line(k, v, indent + 2)
141160
else:
142-
lines.append(f"{prefix}- {item}")
161+
lines.append(f"{prefix}- {_yaml_quote(str(item))}")
143162
elif isinstance(value, bool):
144163
lines.append(f"{prefix}{key}: {str(value).lower()}")
145164
elif isinstance(value, int):
146165
lines.append(f"{prefix}{key}: {value}")
147166
else:
148-
lines.append(f"{prefix}{key}: {value}")
149-
167+
lines.append(f"{prefix}{key}: {_yaml_quote(str(value))}")
168+
150169
for key, value in config.items():
151170
add_line(key, value)
152-
171+
153172
return "\n".join(lines)

common/protocol.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,13 @@
2323
MSG_REQUEST_CONFIG = "request_config"
2424
MSG_CONFIG_RESPONSE = "config_response"
2525

26+
MAX_FRAME_SIZE = 1 * 1024 * 1024 # 1 MiB — JSON 命令帧不应超过此大小
27+
2628

2729
def encode_frame(obj: Dict[str, Any]) -> bytes:
2830
body = json.dumps(obj, ensure_ascii=False, separators=(",", ":")).encode("utf-8")
29-
if len(body) > 0xFFFFFF:
30-
raise ValueError("frame too large")
31+
if len(body) > MAX_FRAME_SIZE:
32+
raise ValueError("frame too large (%d bytes, max %d)" % (len(body), MAX_FRAME_SIZE))
3133
return struct.pack(">I", len(body)) + body
3234

3335

@@ -59,8 +61,8 @@ def recv_exact(conn: socket.socket, n: int) -> bytes:
5961
def read_frame_from_socket(conn: socket.socket) -> Dict[str, Any]:
6062
header = recv_exact(conn, 4)
6163
(n,) = struct.unpack(">I", header)
62-
if n > 16 * 1024 * 1024:
63-
raise ValueError("frame size unreasonable")
64+
if n > MAX_FRAME_SIZE:
65+
raise ValueError("frame size unreasonable (%d bytes, max %d)" % (n, MAX_FRAME_SIZE))
6466
body = recv_exact(conn, n)
6567
obj = json.loads(body.decode("utf-8"))
6668
if not isinstance(obj, dict):

0 commit comments

Comments
 (0)