From 7a4b905ddb64bdc92b7f9acf2ccde9bd84d7a6f3 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Fri, 4 Sep 2026 02:20:48 +0200 Subject: fix(node): pin utf-8 (and LF) on every text file the node reads or writes node.toml, the keystore envelope, the unlock key, the loopback UI token, pairing/invite code files and the denylist were all read and written with the platform default encoding and newline translation. On Windows that is cp1252 + CRLF: a node.toml or keystore holding any non-ASCII byte failed to load, and ops.py's line-based node.toml editor round-tripped CRLF in and LF out. Every read is now `encoding="utf-8"`; every write is `encoding="utf-8", newline="\n"` so the files stay LF whatever the OS. No-op where the locale was already UTF-8. Co-Authored-By: Claude Sonnet 5 --- packages/meshbay-node/src/meshbay_node/ops.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'packages/meshbay-node/src/meshbay_node/ops.py') diff --git a/packages/meshbay-node/src/meshbay_node/ops.py b/packages/meshbay-node/src/meshbay_node/ops.py index 7a8e8ac..40de755 100644 --- a/packages/meshbay-node/src/meshbay_node/ops.py +++ b/packages/meshbay-node/src/meshbay_node/ops.py @@ -453,7 +453,7 @@ async def attach_group(state: dict, name: str, shared_dir: str, if not separate_upload: block += f' upload = true\n' try: - with conf_path.open("a") as f: + with conf_path.open("a", encoding="utf-8", newline="\n") as f: f.write(block) except OSError as e: raise OpError(f"Cannot write {conf_path}: {e}", status=500) from e @@ -485,7 +485,7 @@ async def detach_group(state: dict, name: str) -> dict: group = match[0] conf_path = Path(state.get("config_path") or DEFAULT_CONFIG_PATH) - text = conf_path.read_text() + text = conf_path.read_text(encoding="utf-8") lines = text.split("\n") rng = _find_group_range(lines, group.id) @@ -497,7 +497,7 @@ async def detach_group(state: dict, name: str) -> dict: end += 1 new_lines = lines[:start] + lines[end:] - conf_path.write_text("\n".join(new_lines)) + conf_path.write_text("\n".join(new_lines), encoding="utf-8", newline="\n") log.info("Group detached: %s (%s) removed from %s", group.name, group.id[:8], conf_path) return {"group_id": group.id, "name": group.name, "config": str(conf_path), @@ -534,7 +534,7 @@ def _update_node_toml(conf_path: Path, updates: dict) -> None: """ if not conf_path.exists(): return - text = conf_path.read_text() + text = conf_path.read_text(encoding="utf-8") lines = text.split("\n") node_start = None @@ -575,13 +575,13 @@ def _update_node_toml(conf_path: Path, updates: dict) -> None: lines.insert(node_end, _format_value(key, value)) node_end += 1 - conf_path.write_text("\n".join(lines)) + conf_path.write_text("\n".join(lines), encoding="utf-8", newline="\n") def _insert_roots_block(conf_path: Path, group_id: str, root_block: str) -> None: """Append a [[groups.roots]] block inside the matching [[groups]] section.""" - text = conf_path.read_text() + text = conf_path.read_text(encoding="utf-8") lines = text.split("\n") rng = _find_group_range(lines, group_id) @@ -597,13 +597,13 @@ def _insert_roots_block(conf_path: Path, group_id: str, + [""] + root_block.rstrip("\n").split("\n") + lines[insert_at:]) - conf_path.write_text("\n".join(new_lines)) + conf_path.write_text("\n".join(new_lines), encoding="utf-8", newline="\n") def _remove_roots_block(conf_path: Path, group_id: str, resolved_path: str) -> None: """Remove a [[groups.roots]] block whose resolved path matches.""" - text = conf_path.read_text() + text = conf_path.read_text(encoding="utf-8") lines = text.split("\n") rng = _find_group_range(lines, group_id) @@ -631,7 +631,7 @@ def _remove_roots_block(conf_path: Path, group_id: str, if rm_start > 0 and lines[rm_start - 1].strip() == "": rm_start -= 1 new_lines = lines[:rm_start] + lines[rs_end:] - conf_path.write_text("\n".join(new_lines)) + conf_path.write_text("\n".join(new_lines), encoding="utf-8", newline="\n") return raise OpError(f"Root path not found in config", status=404) -- cgit v1.2.3