|
14 | 14 | import tarfile |
15 | 15 | from io import BytesIO |
16 | 16 | from functools import partial |
| 17 | +from utils_safe_extract import safe_tar_extract, safe_zip_extract |
17 | 18 |
|
18 | 19 | from PyQt6 import QtWidgets, QtCore |
19 | 20 | from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QLineEdit, QPushButton, QTextEdit, QComboBox, QFileDialog, QCheckBox, QHBoxLayout, QVBoxLayout, QProgressDialog |
@@ -454,7 +455,7 @@ def _extract_ffmpeg_zip(self, zip_bytes): |
454 | 455 | base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), 'bin')) |
455 | 456 | os.makedirs(base_dir, exist_ok=True) |
456 | 457 | with zipfile.ZipFile(BytesIO(zip_bytes)) as zf: |
457 | | - self._safe_zip_extract(zf, base_dir) |
| 458 | + safe_zip_extract(zf, base_dir) |
458 | 459 | # try to find ffmpeg(.exe) |
459 | 460 | ffmpeg_path = None |
460 | 461 | for root, dirs, files in os.walk(base_dir): |
@@ -498,7 +499,7 @@ def worker(): |
498 | 499 | base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), 'bin')) |
499 | 500 | os.makedirs(base_dir, exist_ok=True) |
500 | 501 | with tarfile.open(fileobj=BytesIO(content), mode='r:xz') as tf: |
501 | | - self._safe_tar_extract(tf, base_dir) |
| 502 | + safe_tar_extract(tf, base_dir) |
502 | 503 | # procurar binário |
503 | 504 | ffmpeg_path = None |
504 | 505 | for root, dirs, files in os.walk(base_dir): |
@@ -561,36 +562,7 @@ def show_info_msg(self, msg): |
561 | 562 | def show_error_msg(self, msg): |
562 | 563 | QtWidgets.QMessageBox.critical(self, 'Erro', msg) |
563 | 564 |
|
564 | | - # ---- security helpers ---- |
565 | | - def _safe_tar_extract(self, tf: tarfile.TarFile, base_dir: str): |
566 | | - base = os.path.realpath(base_dir) |
567 | | - for member in tf.getmembers(): |
568 | | - member_path = os.path.realpath(os.path.join(base, member.name)) |
569 | | - if not member_path.startswith(base + os.sep) and member_path != base: |
570 | | - raise RuntimeError(f"Entrada insegura no tar: {member.name}") |
571 | | - tf.extractall(base) |
572 | | - |
573 | | - def _safe_zip_extract(self, zf: zipfile.ZipFile, base_dir: str): |
574 | | - base = os.path.realpath(base_dir) |
575 | | - for zi in zf.infolist(): |
576 | | - name = zi.filename |
577 | | - # reject absolute paths or drive letters |
578 | | - if os.path.isabs(name) or ( |
579 | | - len(name) > 1 and name[1] == ':' |
580 | | - ): |
581 | | - raise RuntimeError(f"Entrada insegura no zip (absoluta): {name}") |
582 | | - dest = os.path.realpath(os.path.join(base, name)) |
583 | | - if not dest.startswith(base + os.sep) and dest != base: |
584 | | - raise RuntimeError(f"Entrada insegura no zip: {name}") |
585 | | - # after validation, extract members |
586 | | - for zi in zf.infolist(): |
587 | | - dest = os.path.realpath(os.path.join(base, zi.filename)) |
588 | | - if zi.is_dir() or zi.filename.endswith('/'): |
589 | | - os.makedirs(dest, exist_ok=True) |
590 | | - continue |
591 | | - os.makedirs(os.path.dirname(dest), exist_ok=True) |
592 | | - with zf.open(zi, 'r') as src, open(dest, 'wb') as out: |
593 | | - out.write(src.read()) |
| 565 | + # ---- security helpers moved to utils_safe_extract ---- |
594 | 566 |
|
595 | 567 | if __name__ == '__main__': |
596 | 568 | app = QApplication(sys.argv) |
|
0 commit comments