diff --git a/task_manager.py b/task_manager.py index f64c37e..f515e5c 100644 --- a/task_manager.py +++ b/task_manager.py @@ -27,10 +27,14 @@ class TaskManager: self.db = db def create(self, init_json: dict[str, Any]) -> str: - """POST /init: 建任务, 返回 transfer_id (输入清洗: 文件名/卷数上限)""" - # 文件名字段清洗: 长度上限 + 去路径分隔符/控制字符 + """POST /init: 建任务, 返回 transfer_id (输入清洗: 文件名/卷数上限) + + 文件名只做可打印字符过滤 + 长度截断。不删 / \\ 等路径分隔符: + 加密文件名是 URL-safe base64 (可能含 - _), 路径安全由客户端 _safe_name + 和存储目录 (transfer_id) 保证。 + """ raw = str(init_json.get("file_name", "unnamed")) - clean = "".join(c for c in raw if c.isprintable() and c not in "/\\\x00")[:255] + clean = "".join(c for c in raw if c.isprintable())[:255] init_json["file_name"] = clean or "unnamed" # 卷数上限: 防超大清单放大 (1MB init / 120B 每卷 spec ≈ 8000) chunks = init_json.get("chunks") or [] diff --git a/tests/test_api.py b/tests/test_api.py index a9beb39..18bcced 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -132,7 +132,7 @@ class ServerPipelineTest(unittest.TestCase): self.assertEqual(st["status"], "done") def test_init_sanitizes_file_name(self): - # 恶意文件名: 路径分隔符/控制字符清洗, 长度截断 + # 恶意文件名: 控制字符删除 + 长度截断 (路径分隔符保留, 由客户端 _safe_name 兜底) init_json, chunk_files, _ = _prepare( self.client_kr, os.urandom(64 << 10) ) @@ -147,9 +147,9 @@ class ServerPipelineTest(unittest.TestCase): "SELECT file_name FROM files WHERE file_id = ?", (file_id,) ).fetchone() name = row["file_name"] - self.assertNotIn("/", name) - self.assertNotIn("\\", name) + self.assertNotIn("\x00", name) # 控制字符被删 self.assertLessEqual(len(name), 255) + self.assertIn("..", name) # 路径段保留 (加密名含 - _ 不受影响, 明文名由下载端消毒) def test_init_oversized_json_rejected(self): # init json 超大 -> 413