|
30 | 30 | import pandas as pd |
31 | 31 | from math import ceil |
32 | 32 | from io import StringIO |
| 33 | +from pathlib import Path |
33 | 34 | from functools import wraps |
34 | 35 | from threading import Thread |
35 | 36 | from lazyown import LazyOwnShell |
@@ -98,15 +99,52 @@ def clean_json(texto): |
98 | 99 | def load_yaml_safely(file_path): |
99 | 100 | """Load a YAML file safely with error handling and default values.""" |
100 | 101 | try: |
101 | | - with open(file_path, 'r') as f: |
| 102 | + |
| 103 | + path = Path(file_path) |
| 104 | + |
| 105 | + |
| 106 | + if '..' in path.parts: |
| 107 | + logger.error(f"Path traversal attempt detected: {file_path}") |
| 108 | + return None |
| 109 | + |
| 110 | + |
| 111 | + resolved_path = path.resolve() |
| 112 | + |
| 113 | + |
| 114 | + if resolved_path.suffix.lower() not in ['.yml', '.yaml']: |
| 115 | + logger.error(f"Invalid file extension: {file_path}") |
| 116 | + return None |
| 117 | + |
| 118 | + |
| 119 | + if not resolved_path.exists(): |
| 120 | + logger.error(f"YAML file not found: {resolved_path}") |
| 121 | + return None |
| 122 | + |
| 123 | + if not resolved_path.is_file(): |
| 124 | + logger.error(f"Path is not a regular file: {resolved_path}") |
| 125 | + return None |
| 126 | + |
| 127 | + if not os.access(resolved_path, os.R_OK): |
| 128 | + logger.error(f"No read permission for file: {resolved_path}") |
| 129 | + return None |
| 130 | + |
| 131 | + file_size = resolved_path.stat().st_size |
| 132 | + max_size = 10 * 1024 * 1024 |
| 133 | + if file_size > max_size: |
| 134 | + logger.error(f"File too large ({file_size} bytes): {resolved_path}") |
| 135 | + return None |
| 136 | + |
| 137 | + with open(resolved_path, 'r', encoding='utf-8') as f: |
102 | 138 | data = yaml.safe_load(f) |
| 139 | + |
103 | 140 | if not data: |
104 | | - logger.error(f"Empty YAML file: {file_path}") |
| 141 | + logger.error(f"Empty YAML file: {resolved_path}") |
105 | 142 | return None |
106 | 143 |
|
107 | 144 | data.setdefault('beacon_url', '') |
108 | 145 | data.setdefault('created_at', datetime.now(timezone.utc).isoformat()) |
109 | 146 | return data |
| 147 | + |
110 | 148 | except yaml.YAMLError as e: |
111 | 149 | logger.error(f"Invalid YAML in {file_path}: {e}") |
112 | 150 | return None |
@@ -1263,7 +1301,7 @@ def is_valid_url(url): |
1263 | 1301 | if parsed_url.scheme == 'file' or not parsed_url.scheme: |
1264 | 1302 | file_path = parsed_url.path if parsed_url.scheme == 'file' else url |
1265 | 1303 | file_path = os.path.abspath(file_path) |
1266 | | - if os.path.exists(file_path) and os.path.isfile(file_path): |
| 1304 | + if os.path.exists(file_path) and os.path.isfile(file_path): #TODO BUGFIX |
1267 | 1305 | logging.info(f"Valid local file: {file_path}") |
1268 | 1306 | return True |
1269 | 1307 | logging.warning(f"Local file does not exist or is not a file: {file_path}") |
|
0 commit comments