mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
linux installer script: Do not use the filesystem to pass the downloaded tarball to tar as it is possible for malicuous code running on the users computer to alter the download file between signature verification and calling tar to extract the files.
This commit is contained in:
parent
893799249b
commit
10dfa877d2
@ -7,7 +7,7 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import sys, os, shutil, subprocess, re, platform, time, signal, tempfile, hashlib, errno
|
||||
import sys, os, shutil, subprocess, re, platform, signal, tempfile, hashlib, errno
|
||||
import ssl, socket
|
||||
from contextlib import closing
|
||||
|
||||
@ -241,14 +241,13 @@ def clean_cache(cache, fname):
|
||||
|
||||
def check_signature(dest, signature):
|
||||
if not os.path.exists(dest):
|
||||
return False
|
||||
return None
|
||||
m = hashlib.sha512()
|
||||
with open(dest, 'rb') as f:
|
||||
raw = True
|
||||
while raw:
|
||||
raw = f.read(1024*1024)
|
||||
m.update(raw)
|
||||
return m.hexdigest().encode('ascii') == signature
|
||||
raw = f.read()
|
||||
m.update(raw)
|
||||
if m.hexdigest().encode('ascii') == signature:
|
||||
return raw
|
||||
|
||||
class URLOpener(urllib.FancyURLopener):
|
||||
|
||||
@ -299,9 +298,10 @@ def download_tarball():
|
||||
os.makedirs(cache)
|
||||
clean_cache(cache, fname)
|
||||
dest = os.path.join(cache, fname)
|
||||
if check_signature(dest, signature):
|
||||
raw = check_signature(dest, signature)
|
||||
if raw is not None:
|
||||
print ('Using previously downloaded', fname)
|
||||
return dest
|
||||
return raw
|
||||
cached_sigf = dest +'.signature'
|
||||
cached_sig = None
|
||||
if os.path.exists(cached_sigf):
|
||||
@ -320,12 +320,13 @@ def download_tarball():
|
||||
raise SystemExit(1)
|
||||
do_download(dest)
|
||||
prints('Checking downloaded file integrity...')
|
||||
if not check_signature(dest, signature):
|
||||
raw = check_signature(dest, signature)
|
||||
if raw is None:
|
||||
os.remove(dest)
|
||||
print ('The downloaded files\' signature does not match. '
|
||||
'Try the download again later.')
|
||||
raise SystemExit(1)
|
||||
return dest
|
||||
return raw
|
||||
# }}}
|
||||
|
||||
# Get tarball signature securely {{{
|
||||
@ -581,14 +582,16 @@ def get_https_resource_securely(url, timeout=60, max_redirects=5, ssl_version=No
|
||||
return response.read()
|
||||
# }}}
|
||||
|
||||
def extract_tarball(tar, destdir):
|
||||
def extract_tarball(raw, destdir):
|
||||
prints('Extracting application files...')
|
||||
if hasattr(tar, 'read'):
|
||||
tar = tar.name
|
||||
with open('/dev/null', 'w') as null:
|
||||
subprocess.check_call(['tar', 'xjof', tar, '-C', destdir], stdout=null,
|
||||
p = subprocess.Popen(['tar', 'xjof', '-', '-C', destdir], stdout=null, stdin=subprocess.PIPE, close_fds=True,
|
||||
preexec_fn=lambda:
|
||||
signal.signal(signal.SIGPIPE, signal.SIG_DFL))
|
||||
p.stdin.write(raw)
|
||||
p.stdin.close()
|
||||
if p.wait() != 0:
|
||||
prints('Extracting of application files failed with error code: %s' % p.returncode)
|
||||
|
||||
def get_tarball_info():
|
||||
global signature, calibre_version
|
||||
@ -603,24 +606,14 @@ def get_tarball_info():
|
||||
|
||||
def download_and_extract(destdir):
|
||||
get_tarball_info()
|
||||
try:
|
||||
f = download_tarball()
|
||||
except:
|
||||
raise
|
||||
print('Failed to download, retrying in 30 seconds...')
|
||||
time.sleep(30)
|
||||
try:
|
||||
f = download_tarball()
|
||||
except:
|
||||
print('Failed to download, aborting')
|
||||
sys.exit(1)
|
||||
raw = download_tarball()
|
||||
|
||||
if os.path.exists(destdir):
|
||||
shutil.rmtree(destdir)
|
||||
os.makedirs(destdir)
|
||||
|
||||
print('Extracting files to %s ...'%destdir)
|
||||
extract_tarball(f, destdir)
|
||||
extract_tarball(raw, destdir)
|
||||
|
||||
def check_version():
|
||||
global calibre_version
|
||||
|
Loading…
x
Reference in New Issue
Block a user