mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-03 05:51:15 +02:00
feat: Add API endpoint to list node files
Implement issue #2719 - Add API endpoint to list project files - Add GET /v3/projects/{project_id}/nodes/{node_id}/files endpoint - Add list_node_files() method to Project class - Add security checks to prevent path traversal - Filter out .ghost temporary files - Return file paths with MD5 checksums - Require Node.Audit privilege This allows users to discover dynamically created files such as QEMU disk images created via the disk image API. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
e0860555ba
commit
5b75d633aa
3 files changed
+69
No files matched your search
@@ -20,6 +20,7 @@ import asyncio
|
||||
import hashlib
|
||||
|
||||
from uuid import UUID, uuid4
|
||||
from fastapi import HTTPException
|
||||
|
||||
from gns3server.compute.compute_error import ComputeError, ComputeNotFoundError, ComputeForbiddenError
|
||||
from .port_manager import PortManager
|
||||
@@ -417,6 +418,43 @@ class Project:
|
||||
|
||||
return files
|
||||
|
||||
async def list_node_files(self, node_path: str):
|
||||
"""
|
||||
List files in a specific node directory.
|
||||
|
||||
:param node_path: Relative path to node directory (e.g., "project-files/qemu/node-id")
|
||||
:returns: Array of files in the node directory
|
||||
"""
|
||||
|
||||
node_full_path = os.path.normpath(os.path.join(self.path, node_path))
|
||||
|
||||
# Security check: ensure the path is within the project directory
|
||||
if not os.path.commonpath([node_full_path, self.path]) == self.path:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="Path is outside the project directory")
|
||||
|
||||
if not os.path.exists(node_full_path):
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="Node directory not found")
|
||||
|
||||
files = []
|
||||
try:
|
||||
for filename in os.listdir(node_full_path):
|
||||
file_path = os.path.join(node_full_path, filename)
|
||||
if os.path.isfile(file_path) and not filename.endswith(".ghost"):
|
||||
file_info = {"path": filename}
|
||||
try:
|
||||
file_info["md5sum"] = await wait_run_in_executor(
|
||||
self._hash_file, file_path
|
||||
)
|
||||
except OSError:
|
||||
continue
|
||||
files.append(file_info)
|
||||
except OSError as e:
|
||||
log.error(f"Error listing node files: {e}")
|
||||
|
||||
return files
|
||||
|
||||
def _hash_file(self, path):
|
||||
"""
|
||||
Compute and md5 hash for file
|
||||
|
||||
Reference in new issue
Block a user