From adccef4757f8b1537fa067aacdbffad9b9b27f71 Mon Sep 17 00:00:00 2001 From: DavHau Date: Tue, 12 Aug 2025 22:47:06 +0700 Subject: [PATCH] install: fix torify package not available --- pkgs/clan-cli/clan_lib/machines/install.py | 6 ++++-- pkgs/clan-cli/clan_lib/network/qr_code.py | 7 ++++++- pkgs/clan-cli/clan_lib/network/tor/__init__.py | 3 ++- pkgs/clan-cli/clan_lib/nix/allowed-packages.json | 1 + pkgs/clan-cli/clan_lib/ssh/remote.py | 5 +++-- pkgs/clan-cli/clan_lib/ssh/socks_wrapper.py | 16 ++++++++++++++++ 6 files changed, 32 insertions(+), 6 deletions(-) create mode 100644 pkgs/clan-cli/clan_lib/ssh/socks_wrapper.py diff --git a/pkgs/clan-cli/clan_lib/machines/install.py b/pkgs/clan-cli/clan_lib/machines/install.py index 57b6f6fef..3d8fd2741 100644 --- a/pkgs/clan-cli/clan_lib/machines/install.py +++ b/pkgs/clan-cli/clan_lib/machines/install.py @@ -187,11 +187,13 @@ def run_machine_install(opts: InstallOptions, target_host: Remote) -> None: cmd.append(target_host.target) if target_host.socks_port: # nix copy does not support socks5 proxy, use wrapper command - wrapper_cmd = target_host.socks_wrapper or ["torify"] + wrapper = target_host.socks_wrapper + wrapper_cmd = wrapper.cmd if wrapper else [] + wrapper_packages = wrapper.packages if wrapper else [] cmd = nix_shell( [ "nixos-anywhere", - *wrapper_cmd, + *wrapper_packages, ], [*wrapper_cmd, *cmd], ) diff --git a/pkgs/clan-cli/clan_lib/network/qr_code.py b/pkgs/clan-cli/clan_lib/network/qr_code.py index 7000e6720..c8b77fa84 100644 --- a/pkgs/clan-cli/clan_lib/network/qr_code.py +++ b/pkgs/clan-cli/clan_lib/network/qr_code.py @@ -12,6 +12,7 @@ from clan_lib.flake import Flake from clan_lib.network.network import Network, Peer from clan_lib.nix import nix_shell from clan_lib.ssh.remote import Remote +from clan_lib.ssh.socks_wrapper import tor_wrapper log = logging.getLogger(__name__) @@ -110,7 +111,11 @@ def read_qr_json(qr_data: dict[str, Any], flake: Flake) -> QRCodeData: remote = Remote.from_ssh_uri( machine_name="installer-tor", address=tor_addr, - ).override(password=password, socks_port=9050, socks_wrapper=["torify"]) + ).override( + password=password, + socks_port=9050, + socks_wrapper=tor_wrapper, + ) addresses.append(RemoteWithNetwork(network=network, remote=remote)) diff --git a/pkgs/clan-cli/clan_lib/network/tor/__init__.py b/pkgs/clan-cli/clan_lib/network/tor/__init__.py index 775db39f0..9dd2af1ed 100644 --- a/pkgs/clan-cli/clan_lib/network/tor/__init__.py +++ b/pkgs/clan-cli/clan_lib/network/tor/__init__.py @@ -9,6 +9,7 @@ from clan_lib.errors import ClanError from clan_lib.network import Network, NetworkTechnologyBase, Peer from clan_lib.network.tor.lib import is_tor_running, spawn_tor from clan_lib.ssh.remote import Remote +from clan_lib.ssh.socks_wrapper import tor_wrapper if TYPE_CHECKING: from clan_lib.ssh.remote import Remote @@ -57,5 +58,5 @@ class NetworkTechnology(NetworkTechnologyBase): address=peer.host, command_prefix=peer.name, socks_port=self.proxy, - socks_wrapper=["torify"], + socks_wrapper=tor_wrapper, ) diff --git a/pkgs/clan-cli/clan_lib/nix/allowed-packages.json b/pkgs/clan-cli/clan_lib/nix/allowed-packages.json index d723bc8e1..88f39e8b2 100644 --- a/pkgs/clan-cli/clan_lib/nix/allowed-packages.json +++ b/pkgs/clan-cli/clan_lib/nix/allowed-packages.json @@ -28,6 +28,7 @@ "sops", "sshpass", "tor", + "torsocks", "util-linux", "virt-viewer", "virtiofsd", diff --git a/pkgs/clan-cli/clan_lib/ssh/remote.py b/pkgs/clan-cli/clan_lib/ssh/remote.py index 1894cf0ab..c2ee50abe 100644 --- a/pkgs/clan-cli/clan_lib/ssh/remote.py +++ b/pkgs/clan-cli/clan_lib/ssh/remote.py @@ -18,6 +18,7 @@ from clan_lib.errors import ClanError, indent_command # Assuming these are avai from clan_lib.nix import nix_shell from clan_lib.ssh.host_key import HostKeyCheck, hostkey_to_ssh_opts from clan_lib.ssh.parse import parse_ssh_uri +from clan_lib.ssh.socks_wrapper import SocksWrapper from clan_lib.ssh.sudo_askpass_proxy import SudoAskpassProxy if TYPE_CHECKING: @@ -42,7 +43,7 @@ class Remote: verbose_ssh: bool = False ssh_options: dict[str, str] = field(default_factory=dict) socks_port: int | None = None - socks_wrapper: list[str] | None = None + socks_wrapper: SocksWrapper | None = None _control_path_dir: Path | None = None _askpass_path: str | None = None @@ -63,7 +64,7 @@ class Remote: private_key: Path | None = None, password: str | None = None, socks_port: int | None = None, - socks_wrapper: list[str] | None = None, + socks_wrapper: SocksWrapper | None = None, command_prefix: str | None = None, port: int | None = None, ssh_options: dict[str, str] | None = None, diff --git a/pkgs/clan-cli/clan_lib/ssh/socks_wrapper.py b/pkgs/clan-cli/clan_lib/ssh/socks_wrapper.py new file mode 100644 index 000000000..d4da1b811 --- /dev/null +++ b/pkgs/clan-cli/clan_lib/ssh/socks_wrapper.py @@ -0,0 +1,16 @@ +from dataclasses import dataclass + + +@dataclass(frozen=True) +class SocksWrapper: + """Configuration for SOCKS proxy wrapper commands.""" + + # The command to execute for wrapping network connections through SOCKS (e.g., ["torify"]) + cmd: list[str] + + # Nix packages required to provide the wrapper command (e.g., ["tor", "torsocks"]) + packages: list[str] + + +# Pre-configured Tor wrapper instance +tor_wrapper = SocksWrapper(cmd=["torify"], packages=["tor", "torsocks"])