feat: drhider PDF→DOCX conversion (LibreOffice), collision dialog (v1.9)
Deploy contracts-flask / validate (push) Successful in 0s
Deploy contracts-flask / validate (push) Successful in 0s
This commit is contained in:
@@ -207,6 +207,8 @@ class TwoPassObfuscator:
|
||||
"""
|
||||
# --- Распаковать ZIP-файлы ---
|
||||
files = self._expand_zips(files)
|
||||
# --- Конвертировать PDF → DOCX ---
|
||||
files = self._convert_pdfs_to_docx(files)
|
||||
|
||||
try:
|
||||
# --- Проход 1: сбор сущностей ---
|
||||
@@ -236,10 +238,6 @@ class TwoPassObfuscator:
|
||||
pass
|
||||
elif fname in all_docx:
|
||||
obf_content = self._replace_in_docx(all_docx[fname])
|
||||
elif fname.endswith('.pdf'):
|
||||
txt = all_texts.get(fname, '')
|
||||
obf_content = self._replace_in_text(txt, fname)
|
||||
fname = fname[:-4] + '.txt'
|
||||
else:
|
||||
txt = all_texts.get(fname, '')
|
||||
obf_content = self._replace_in_text(txt, fname)
|
||||
@@ -253,6 +251,46 @@ class TwoPassObfuscator:
|
||||
self._regex_replacements.clear()
|
||||
self._sorted_keys.clear()
|
||||
|
||||
def _convert_pdfs_to_docx(self, files: List[Tuple[str, bytes, str]]) -> List[Tuple[str, bytes, str]]:
|
||||
"""Конвертировать PDF в DOCX через LibreOffice. При совпадении имён — _из_pdf."""
|
||||
import subprocess, tempfile
|
||||
result = []
|
||||
existing_names = {f[0] for f in files}
|
||||
for fname, content, ctype in files:
|
||||
if not fname.lower().endswith('.pdf'):
|
||||
result.append((fname, content, ctype))
|
||||
continue
|
||||
try:
|
||||
with tempfile.NamedTemporaryFile(suffix='.pdf', delete=False) as tmp:
|
||||
tmp.write(content)
|
||||
pdf_path = tmp.name
|
||||
outdir = tempfile.mkdtemp()
|
||||
subprocess.run(['libreoffice', '--headless', '--convert-to', 'docx',
|
||||
'--outdir', outdir, pdf_path], timeout=30, capture_output=True)
|
||||
docx_files = [f for f in os.listdir(outdir) if f.endswith('.docx')]
|
||||
if docx_files:
|
||||
with open(os.path.join(outdir, docx_files[0]), 'rb') as f:
|
||||
docx_content = f.read()
|
||||
new_name = fname[:-4] + '.docx'
|
||||
if new_name in existing_names:
|
||||
new_name = fname[:-4] + '_из_pdf.docx'
|
||||
existing_names.add(new_name)
|
||||
result.append((new_name, docx_content, ctype))
|
||||
else:
|
||||
log.warning("PDF→DOCX failed for %s", fname)
|
||||
result.append((fname, content, ctype))
|
||||
except Exception as e:
|
||||
log.warning("PDF→DOCX error for %s: %s", fname, e)
|
||||
result.append((fname, content, ctype))
|
||||
finally:
|
||||
if os.path.exists(pdf_path):
|
||||
os.unlink(pdf_path)
|
||||
if os.path.exists(outdir):
|
||||
for f in os.listdir(outdir):
|
||||
os.unlink(os.path.join(outdir, f))
|
||||
os.rmdir(outdir)
|
||||
return result
|
||||
|
||||
def _expand_zips(self, files: List[Tuple[str, bytes, str]]) -> List[Tuple[str, bytes, str]]:
|
||||
"""Распаковать ZIP-файлы, заменив их содержимым. Остальные файлы — как есть.
|
||||
Защита от ZIP-бомб: ratio + накопительный размер (как в compare/unzip.py)."""
|
||||
|
||||
Reference in New Issue
Block a user