ssh-licco 2.1.2__tar.gz → 2.1.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. {ssh_licco-2.1.2/ssh_licco.egg-info → ssh_licco-2.1.4}/PKG-INFO +18 -2
  2. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/README.md +17 -1
  3. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/pyproject.toml +1 -1
  4. {ssh_licco-2.1.2 → ssh_licco-2.1.4/ssh_licco.egg-info}/PKG-INFO +18 -2
  5. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/__init__.py +2 -2
  6. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/file_transfer.py +99 -0
  7. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/LICENSE +0 -0
  8. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/setup.cfg +0 -0
  9. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_licco.egg-info/SOURCES.txt +0 -0
  10. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_licco.egg-info/dependency_links.txt +0 -0
  11. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_licco.egg-info/entry_points.txt +0 -0
  12. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_licco.egg-info/requires.txt +0 -0
  13. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_licco.egg-info/top_level.txt +0 -0
  14. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/__main__.py +0 -0
  15. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/approval.py +0 -0
  16. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/audit_logger.py +0 -0
  17. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/batch_executor.py +0 -0
  18. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/cli.py +0 -0
  19. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/clients/__init__.py +0 -0
  20. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/clients/additional_clients.py +0 -0
  21. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/clients/factory.py +0 -0
  22. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/clients/interface.py +0 -0
  23. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/clients/paramiko_client.py +0 -0
  24. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/config_manager.py +0 -0
  25. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/connection_config.py +0 -0
  26. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/connection_pool.py +0 -0
  27. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/exceptions.py +0 -0
  28. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/executor.py +0 -0
  29. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/__init__.py +0 -0
  30. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/approval.py +0 -0
  31. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/connect.py +0 -0
  32. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/context.py +0 -0
  33. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/docker.py +0 -0
  34. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/execute.py +0 -0
  35. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/host.py +0 -0
  36. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/key.py +0 -0
  37. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/process.py +0 -0
  38. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/schemas.py +0 -0
  39. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/session.py +0 -0
  40. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/handlers/utils.py +0 -0
  41. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/key_manager.py +0 -0
  42. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/logging_config.py +0 -0
  43. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/runtime_guard.py +0 -0
  44. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/secret_provider.py +0 -0
  45. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/security.py +0 -0
  46. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/server.py +0 -0
  47. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/service.py +0 -0
  48. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/session_manager.py +0 -0
  49. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/tunnel.py +0 -0
  50. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/ssh_mcp/watchdog.py +0 -0
  51. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/tests/test_config_manager.py +0 -0
  52. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/tests/test_key_manager.py +0 -0
  53. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/tests/test_security.py +0 -0
  54. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/tests/test_server.py +0 -0
  55. {ssh_licco-2.1.2 → ssh_licco-2.1.4}/tests/test_session_manager.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ssh-licco
3
- Version: 2.1.2
3
+ Version: 2.1.4
4
4
  Summary: SSH Model Context Protocol Server - Enable SSH functionality for AI models
5
5
  Author-email: SSH LICCO Team <contact@ssh-licco.dev>
6
6
  License: MIT
@@ -86,8 +86,24 @@ Dynamic: license-file
86
86
  - 🐳 **Docker 支持** - Docker 构建和状态监控
87
87
  - 📋 **后台任务** - 可靠的后台进程启动(nohup + bash -c 包装,单次 SSH 调用无竞态)
88
88
  - 🖥️ **screen/tmux 会话** - 持久化远程会话,SSH 断开后进程依然存活
89
+ - 🪟 **Windows 服务器支持** - 支持 Windows Server(OpenSSH for Windows)与 Linux/macOS 目标主机
89
90
  - 🔍 **进程管理** - 启动/停止/查询远程进程、SSH 端口转发(tunnel)
90
91
  - 🔍 **看门狗** - 任务监控、心跳检测、全局异常处理
92
+ - 🛡️ **文件传输路径安全校验** - `ssh_file_transfer` delete 自动识别 Windows / Unix 路径风格并拦截敏感路径与路径遍历
93
+
94
+ ---
95
+
96
+ ## 🖥️ 目标主机支持
97
+
98
+ SSH-LICCO 基于标准 SSH/SFTP 协议,可连接以下目标主机:
99
+
100
+ | 操作系统 | 要求 | 备注 |
101
+ |---|---|---|
102
+ | **Linux** | OpenSSH 7.0+ | 推荐,完整支持所有功能 |
103
+ | **Windows Server** | OpenSSH for Windows / PowerShell Remoting over SSH | v2.1.3+ 支持 Windows 路径风格与安全校验 |
104
+ | **macOS** | 系统内置 OpenSSH | 完整支持 |
105
+
106
+ > **提示**:连接 Windows 服务器时,请使用 Windows 风格路径(如 `C:\temp\file.txt`),系统会自动识别并进行路径安全校验。
91
107
 
92
108
  ---
93
109
 
@@ -241,7 +257,7 @@ SSH 跳板模式部署的生产必做加固,补齐跳板机单点风险:
241
257
  | `ssh_connect` | 连接管理 | 自动读取环境变量/配置,支持密码+密钥认证,可保存配置,登录后自动执行命令 |
242
258
  | `ssh_execute` | 命令执行 | 自动连接、智能后台检测、长任务等待、超时控制,支持 nohup/screen/tmux 三种后台模式;v2.1.0 新增 `approval_id`(高危审批)与 `remote_guard`(双层拦截)参数 |
243
259
  | `ssh_disconnect` | 会话管理 | 断开指定会话 OR 列出所有活跃会话 |
244
- | `ssh_file_transfer` | 文件传输 | 上传/下载/列表/写入/追加/删除/创建目录/查看元信息(8 种操作) |
260
+ | `ssh_file_transfer` | 文件传输 | 上传/下载/列表/写入/追加/删除/创建目录/查看元信息(8 种操作);v2.1.3+ delete 操作新增 Windows/Unix 敏感路径拦截与路径遍历防护 |
245
261
  | `ssh_host` | 主机管理 | `action=list/add/remove` 增删查主机配置 |
246
262
  | `ssh_docker` | Docker 管理 | `action=ps/images/build/logs` 全生命周期管理 |
247
263
  | `ssh_generate_key` | 密钥生成 | RSA / Ed25519 密钥对 |
@@ -53,8 +53,24 @@
53
53
  - 🐳 **Docker 支持** - Docker 构建和状态监控
54
54
  - 📋 **后台任务** - 可靠的后台进程启动(nohup + bash -c 包装,单次 SSH 调用无竞态)
55
55
  - 🖥️ **screen/tmux 会话** - 持久化远程会话,SSH 断开后进程依然存活
56
+ - 🪟 **Windows 服务器支持** - 支持 Windows Server(OpenSSH for Windows)与 Linux/macOS 目标主机
56
57
  - 🔍 **进程管理** - 启动/停止/查询远程进程、SSH 端口转发(tunnel)
57
58
  - 🔍 **看门狗** - 任务监控、心跳检测、全局异常处理
59
+ - 🛡️ **文件传输路径安全校验** - `ssh_file_transfer` delete 自动识别 Windows / Unix 路径风格并拦截敏感路径与路径遍历
60
+
61
+ ---
62
+
63
+ ## 🖥️ 目标主机支持
64
+
65
+ SSH-LICCO 基于标准 SSH/SFTP 协议,可连接以下目标主机:
66
+
67
+ | 操作系统 | 要求 | 备注 |
68
+ |---|---|---|
69
+ | **Linux** | OpenSSH 7.0+ | 推荐,完整支持所有功能 |
70
+ | **Windows Server** | OpenSSH for Windows / PowerShell Remoting over SSH | v2.1.3+ 支持 Windows 路径风格与安全校验 |
71
+ | **macOS** | 系统内置 OpenSSH | 完整支持 |
72
+
73
+ > **提示**:连接 Windows 服务器时,请使用 Windows 风格路径(如 `C:\temp\file.txt`),系统会自动识别并进行路径安全校验。
58
74
 
59
75
  ---
60
76
 
@@ -208,7 +224,7 @@ SSH 跳板模式部署的生产必做加固,补齐跳板机单点风险:
208
224
  | `ssh_connect` | 连接管理 | 自动读取环境变量/配置,支持密码+密钥认证,可保存配置,登录后自动执行命令 |
209
225
  | `ssh_execute` | 命令执行 | 自动连接、智能后台检测、长任务等待、超时控制,支持 nohup/screen/tmux 三种后台模式;v2.1.0 新增 `approval_id`(高危审批)与 `remote_guard`(双层拦截)参数 |
210
226
  | `ssh_disconnect` | 会话管理 | 断开指定会话 OR 列出所有活跃会话 |
211
- | `ssh_file_transfer` | 文件传输 | 上传/下载/列表/写入/追加/删除/创建目录/查看元信息(8 种操作) |
227
+ | `ssh_file_transfer` | 文件传输 | 上传/下载/列表/写入/追加/删除/创建目录/查看元信息(8 种操作);v2.1.3+ delete 操作新增 Windows/Unix 敏感路径拦截与路径遍历防护 |
212
228
  | `ssh_host` | 主机管理 | `action=list/add/remove` 增删查主机配置 |
213
229
  | `ssh_docker` | Docker 管理 | `action=ps/images/build/logs` 全生命周期管理 |
214
230
  | `ssh_generate_key` | 密钥生成 | RSA / Ed25519 密钥对 |
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ssh-licco"
3
- version = "2.1.2"
3
+ version = "2.1.4"
4
4
  description = "SSH Model Context Protocol Server - Enable SSH functionality for AI models"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ssh-licco
3
- Version: 2.1.2
3
+ Version: 2.1.4
4
4
  Summary: SSH Model Context Protocol Server - Enable SSH functionality for AI models
5
5
  Author-email: SSH LICCO Team <contact@ssh-licco.dev>
6
6
  License: MIT
@@ -86,8 +86,24 @@ Dynamic: license-file
86
86
  - 🐳 **Docker 支持** - Docker 构建和状态监控
87
87
  - 📋 **后台任务** - 可靠的后台进程启动(nohup + bash -c 包装,单次 SSH 调用无竞态)
88
88
  - 🖥️ **screen/tmux 会话** - 持久化远程会话,SSH 断开后进程依然存活
89
+ - 🪟 **Windows 服务器支持** - 支持 Windows Server(OpenSSH for Windows)与 Linux/macOS 目标主机
89
90
  - 🔍 **进程管理** - 启动/停止/查询远程进程、SSH 端口转发(tunnel)
90
91
  - 🔍 **看门狗** - 任务监控、心跳检测、全局异常处理
92
+ - 🛡️ **文件传输路径安全校验** - `ssh_file_transfer` delete 自动识别 Windows / Unix 路径风格并拦截敏感路径与路径遍历
93
+
94
+ ---
95
+
96
+ ## 🖥️ 目标主机支持
97
+
98
+ SSH-LICCO 基于标准 SSH/SFTP 协议,可连接以下目标主机:
99
+
100
+ | 操作系统 | 要求 | 备注 |
101
+ |---|---|---|
102
+ | **Linux** | OpenSSH 7.0+ | 推荐,完整支持所有功能 |
103
+ | **Windows Server** | OpenSSH for Windows / PowerShell Remoting over SSH | v2.1.3+ 支持 Windows 路径风格与安全校验 |
104
+ | **macOS** | 系统内置 OpenSSH | 完整支持 |
105
+
106
+ > **提示**:连接 Windows 服务器时,请使用 Windows 风格路径(如 `C:\temp\file.txt`),系统会自动识别并进行路径安全校验。
91
107
 
92
108
  ---
93
109
 
@@ -241,7 +257,7 @@ SSH 跳板模式部署的生产必做加固,补齐跳板机单点风险:
241
257
  | `ssh_connect` | 连接管理 | 自动读取环境变量/配置,支持密码+密钥认证,可保存配置,登录后自动执行命令 |
242
258
  | `ssh_execute` | 命令执行 | 自动连接、智能后台检测、长任务等待、超时控制,支持 nohup/screen/tmux 三种后台模式;v2.1.0 新增 `approval_id`(高危审批)与 `remote_guard`(双层拦截)参数 |
243
259
  | `ssh_disconnect` | 会话管理 | 断开指定会话 OR 列出所有活跃会话 |
244
- | `ssh_file_transfer` | 文件传输 | 上传/下载/列表/写入/追加/删除/创建目录/查看元信息(8 种操作) |
260
+ | `ssh_file_transfer` | 文件传输 | 上传/下载/列表/写入/追加/删除/创建目录/查看元信息(8 种操作);v2.1.3+ delete 操作新增 Windows/Unix 敏感路径拦截与路径遍历防护 |
245
261
  | `ssh_host` | 主机管理 | `action=list/add/remove` 增删查主机配置 |
246
262
  | `ssh_docker` | Docker 管理 | `action=ps/images/build/logs` 全生命周期管理 |
247
263
  | `ssh_generate_key` | 密钥生成 | RSA / Ed25519 密钥对 |
@@ -1,8 +1,8 @@
1
1
  # SSH-LICCO 版本信息
2
2
  # 所有代码中的版本信息都从这里读取
3
- # 版本号:2.1.2
3
+ # 版本号:2.1.4
4
4
 
5
- __version__ = "2.1.2"
5
+ __version__ = "2.1.4"
6
6
  __author__ = "Li Qi"
7
7
  __email__ = "1985694657@qq.com"
8
8
  __license__ = "MIT"
@@ -4,6 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import re
6
6
  import shlex
7
+ from pathlib import PurePosixPath, PureWindowsPath
7
8
 
8
9
  from mcp.types import TextContent
9
10
 
@@ -12,6 +13,101 @@ from .context import HandlerContext
12
13
  from .utils import ensure_session
13
14
 
14
15
 
16
+ # 远程 Unix/Linux 敏感路径黑名单
17
+ FORBIDDEN_REMOTE_PATHS = [
18
+ "/etc",
19
+ "/root",
20
+ "/boot",
21
+ "/proc",
22
+ "/sys",
23
+ "/dev",
24
+ "/bin",
25
+ "/sbin",
26
+ "/usr/bin",
27
+ "/usr/sbin",
28
+ "/lib",
29
+ "/lib64",
30
+ "/var/lib/postgresql",
31
+ "/var/lib/mysql",
32
+ "/var/lib/redis",
33
+ "/var/lib/docker",
34
+ "/var/log",
35
+ "/var/spool",
36
+ "/var/mail",
37
+ "/home/*/.ssh",
38
+ ]
39
+
40
+ # 远程 Windows 敏感路径黑名单(支持大小写不敏感匹配)
41
+ FORBIDDEN_WINDOWS_PATHS = [
42
+ r"C:\Windows",
43
+ r"C:\Windows\System32",
44
+ r"C:\Windows\SysWOW64",
45
+ r"C:\Program Files",
46
+ r"C:\Program Files (x86)",
47
+ r"C:\ProgramData",
48
+ r"C:\inetpub",
49
+ r"C:\Users\Default",
50
+ r"C:\Users\Public",
51
+ r"C:\Recovery",
52
+ r"C:\System Volume Information",
53
+ r"C:\$Recycle.Bin",
54
+ ]
55
+
56
+
57
+ def _is_windows_path(path: str) -> bool:
58
+ """根据路径特征判断是否为 Windows 风格路径。"""
59
+ if re.match(r"^[A-Za-z]:\\", path):
60
+ return True
61
+ if path.startswith("\\\\"):
62
+ return True
63
+ # 仅包含反斜杠且不含正斜杠时,视为 Windows 路径
64
+ if "\\" in path and "/" not in path:
65
+ return True
66
+ return False
67
+
68
+
69
+ def _validate_remote_path(remote_path: str, operation: str = "access") -> tuple[bool, str]:
70
+ """校验远程路径是否安全,自动识别 Windows / Unix 路径风格。
71
+
72
+ Returns:
73
+ (is_safe, error_message)
74
+ """
75
+ if not remote_path or not remote_path.strip():
76
+ return False, "远程路径不能为空"
77
+
78
+ remote_path = remote_path.strip()
79
+
80
+ if _is_windows_path(remote_path):
81
+ # Windows 路径处理
82
+ normalized = str(PureWindowsPath(remote_path))
83
+ if ".." in normalized.split("\\"):
84
+ return False, f"Windows 路径遍历被阻止:{remote_path}"
85
+
86
+ upper_normalized = normalized.upper()
87
+ for forbidden in FORBIDDEN_WINDOWS_PATHS:
88
+ upper_forbidden = forbidden.upper().rstrip("\\")
89
+ if upper_normalized == upper_forbidden or upper_normalized.startswith(upper_forbidden + "\\"):
90
+ return False, f"禁止{operation} Windows 敏感路径:{forbidden}"
91
+
92
+ return True, ""
93
+
94
+ # Unix/Linux 路径处理
95
+ normalized = str(PurePosixPath(remote_path)).rstrip("/") or "/"
96
+ if ".." in normalized.split("/"):
97
+ return False, f"路径遍历被阻止:{remote_path}"
98
+
99
+ path_for_check = normalized.rstrip("/*") or "/"
100
+ for forbidden in FORBIDDEN_REMOTE_PATHS:
101
+ if forbidden.endswith("/*"):
102
+ prefix = forbidden[:-1]
103
+ if path_for_check.startswith(prefix) or path_for_check + "/" == prefix:
104
+ return False, f"禁止{operation}敏感路径:{forbidden}"
105
+ elif path_for_check == forbidden or path_for_check.startswith(forbidden + "/"):
106
+ return False, f"禁止{operation}敏感路径:{forbidden}"
107
+
108
+ return True, ""
109
+
110
+
15
111
  async def handle_file_transfer(ctx: HandlerContext, args: dict) -> list[TextContent]:
16
112
  """Transfer files between local and remote, or perform remote file operations."""
17
113
  session_id = await ensure_session(ctx, args, handle_connect)
@@ -51,6 +147,9 @@ async def handle_file_transfer(ctx: HandlerContext, args: dict) -> list[TextCont
51
147
  elif direction == "delete":
52
148
  if not remote_path:
53
149
  return [TextContent(type="text", text="delete requires remote_path")]
150
+ safe, err = _validate_remote_path(remote_path, operation="delete")
151
+ if not safe:
152
+ return [TextContent(type="text", text=f"❌ Delete blocked: {err}")]
54
153
  result = await session.delete_file(remote_path)
55
154
  elif direction == "mkdir":
56
155
  if not remote_path:
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes