more secure tmp file creation for latex

This commit is contained in:
Yann Leboulanger 2012-04-17 10:45:55 +02:00
parent 395bf4fd99
commit 43b2a1b4f0
1 changed files with 31 additions and 34 deletions

View File

@ -29,7 +29,7 @@
import os import os
import random import random
from tempfile import gettempdir from tempfile import mkstemp, mkdtemp
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
import logging import logging
@ -57,24 +57,6 @@ def check_blacklist(str_):
return True return True
return False return False
def get_tmpfile_name():
random.seed()
nb = 0
while(nb < 100):
int_ = random.randint(0, 10000)
filename = os.path.join(gettempdir(), 'gajimtex_' + int_.__str__())
# Check if a file to not overwrite it
ok = True
extensions = ['.tex', '.log', '.aux', '.dvi']
for ext in extensions:
if os.path.exists(filename + ext):
ok = False
break
if ok:
return filename
nb += 1
return filename
def write_latex(filename, str_): def write_latex(filename, str_):
texstr = '\\documentclass[12pt]{article}\\usepackage[dvips]{graphicx}' texstr = '\\documentclass[12pt]{article}\\usepackage[dvips]{graphicx}'
texstr += '\\usepackage{amsmath}\\usepackage{amssymb}' texstr += '\\usepackage{amsmath}\\usepackage{amssymb}'
@ -91,12 +73,13 @@ def write_latex(filename, str_):
# a wrapper for Popen so that no window gets opened on Windows # a wrapper for Popen so that no window gets opened on Windows
# (i think this is the reason we're using Popen rather than just system()) # (i think this is the reason we're using Popen rather than just system())
# stdout goes to a pipe so that it can be read # stdout goes to a pipe so that it can be read
def popen_nt_friendly(command): def popen_nt_friendly(command, directory):
if os.name == 'nt': if os.name == 'nt':
# CREATE_NO_WINDOW # CREATE_NO_WINDOW
return Popen(command, creationflags=0x08000000, cwd=gettempdir(), stdout=PIPE) return Popen(command, creationflags=0x08000000, cwd=directory,
stdout=PIPE)
else: else:
return Popen(command, cwd=gettempdir(), stdout=PIPE) return Popen(command, cwd=directory, stdout=PIPE)
def check_for_latex_support(): def check_for_latex_support():
""" """
@ -112,16 +95,16 @@ def check_for_latex_support():
except LatexError: except LatexError:
return False return False
def try_run(argv): def try_run(argv, directory):
try: try:
p = popen_nt_friendly(argv) p = popen_nt_friendly(argv, directory)
out = p.communicate()[0] out = p.communicate()[0]
log.info(out) log.info(out)
return p.wait() return p.wait()
except Exception, e: except Exception, e:
return _('Error executing "%(command)s": %(error)s') % { return _('Error executing "%(command)s": %(error)s') % {
'command': " ".join(argv), 'command': " ".join(argv),
'error': helpers.decode_string(str(e))} 'error': helpers.decode_string(str(e))}
def latex_to_image(str_): def latex_to_image(str_):
@ -137,32 +120,41 @@ def latex_to_image(str_):
return [] return []
except AttributeError: except AttributeError:
# interface may not be available when we test latext at startup # interface may not be available when we test latext at startup
return ['-fg', 'rgb 0.0 0.0 0.0'] return {'hex': ['+level-colors', '0x000000'],
'tex': ['-fg', 'rgb 0.0 0.0 0.0']}[fmt]
# filter latex code with bad commands # filter latex code with bad commands
if check_blacklist(str_): if check_blacklist(str_):
# we triggered the blacklist, immediately return None # we triggered the blacklist, immediately return None
return None return None
tmpfile = get_tmpfile_name() try:
tmpdir = mkdtemp(prefix='gajimtex')
tmppng = mkstemp(prefix='gajim_tex', suffix='.png')[1]
except Exception:
raise LatexError('could not securely create one or more temporary files'
' for LaTeX conversion')
tmpfile = os.path.join(tmpdir, 'gajim_tex')
# build latex string # build latex string
write_latex(os.path.join(tmpfile + '.tex'), str_) write_latex(tmpfile + '.tex', str_)
# convert TeX to dvi # convert TeX to dvi
exitcode = try_run(['latex', '--interaction=nonstopmode', exitcode = try_run(['latex', '--interaction=nonstopmode', tmpfile + '.tex'],
tmpfile + '.tex']) tmpdir)
if exitcode == 0: if exitcode == 0:
# convert dvi to png # convert dvi to png
latex_png_dpi = gajim.config.get('latex_png_dpi') latex_png_dpi = gajim.config.get('latex_png_dpi')
exitcode = try_run(['dvipng'] + fg_str('tex') + ['-T', 'tight', '-D', exitcode = try_run(['dvipng'] + fg_str('tex') + ['-T', 'tight', '-D',
latex_png_dpi, tmpfile + '.dvi', '-o', tmpfile + '.png']) latex_png_dpi, tmpfile + '.dvi', '-o', tmpfile + '.png'], tmpdir)
if exitcode: if exitcode:
# dvipng failed, try convert # dvipng failed, try convert
exitcode = try_run(['convert'] + fg_str('hex') + ['-trim', exitcode = try_run(['convert'] + fg_str('hex') + ['-trim',
'-density', latex_png_dpi, tmpfile + '.dvi', tmpfile + '.png']) '-density', latex_png_dpi, tmpfile + '.dvi', tmpfile + '.png'],
tmpdir)
# remove temp files created by us and TeX # remove temp files created by us and TeX
extensions = ['.tex', '.log', '.aux', '.dvi'] extensions = ['.tex', '.log', '.aux', '.dvi']
@ -172,10 +164,15 @@ def latex_to_image(str_):
except Exception: except Exception:
pass pass
if exitcode == 0:
os.rename(tmpfile + '.png', tmppng)
os.rmdir(tmpdir)
if isinstance(exitcode, (unicode, str)): if isinstance(exitcode, (unicode, str)):
raise LatexError(exitcode) raise LatexError(exitcode)
if exitcode == 0: if exitcode == 0:
result = tmpfile + '.png' result = tmppng
return result return result