mirror of
https://gitlab.com/fdroid/fdroidserver.git
synced 2024-11-20 13:50:12 +01:00
update: strip all metadata from PNGs
This strips metadata and optimizes the compression of all PNGs copied from the app's source repo as well as all the icons extracted from the APKs. There have been exploits delivered via image metadata, and F-Droid isn't using it all, so its best to just remove it. This unfortunately uncompresses and recompresses the files. Luckily, that's a lossless procedure with PNGs, and we might end up with smaller files. The only tool I could find that strips without changing the image data is exiftool, but that is written in Perl.
This commit is contained in:
parent
67b9514c5a
commit
387eebc4d6
@ -35,7 +35,7 @@ from argparse import ArgumentParser
|
|||||||
import collections
|
import collections
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image, PngImagePlugin
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from . import _
|
from . import _
|
||||||
@ -84,6 +84,8 @@ GRAPHIC_NAMES = ('featureGraphic', 'icon', 'promoGraphic', 'tvBanner')
|
|||||||
SCREENSHOT_DIRS = ('phoneScreenshots', 'sevenInchScreenshots',
|
SCREENSHOT_DIRS = ('phoneScreenshots', 'sevenInchScreenshots',
|
||||||
'tenInchScreenshots', 'tvScreenshots', 'wearScreenshots')
|
'tenInchScreenshots', 'tvScreenshots', 'wearScreenshots')
|
||||||
|
|
||||||
|
BLANK_PNG_INFO = PngImagePlugin.PngInfo()
|
||||||
|
|
||||||
|
|
||||||
def dpi_to_px(density):
|
def dpi_to_px(density):
|
||||||
return (int(density) * 48) / 160
|
return (int(density) * 48) / 160
|
||||||
@ -371,7 +373,8 @@ def resize_icon(iconpath, density):
|
|||||||
im.thumbnail((size, size), Image.ANTIALIAS)
|
im.thumbnail((size, size), Image.ANTIALIAS)
|
||||||
logging.debug("%s was too large at %s - new size is %s" % (
|
logging.debug("%s was too large at %s - new size is %s" % (
|
||||||
iconpath, oldsize, im.size))
|
iconpath, oldsize, im.size))
|
||||||
im.save(iconpath, "PNG")
|
im.save(iconpath, "PNG", optimize=True,
|
||||||
|
pnginfo=BLANK_PNG_INFO, icc_profile=None)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(_("Failed resizing {path}: {error}".format(path=iconpath, error=e)))
|
logging.error(_("Failed resizing {path}: {error}".format(path=iconpath, error=e)))
|
||||||
@ -677,20 +680,28 @@ def _strip_and_copy_image(inpath, outpath):
|
|||||||
|
|
||||||
Sadly, image metadata like EXIF can be used to exploit devices.
|
Sadly, image metadata like EXIF can be used to exploit devices.
|
||||||
It is not used at all in the F-Droid ecosystem, so its much safer
|
It is not used at all in the F-Droid ecosystem, so its much safer
|
||||||
just to remove it entirely. PNG does not have the same kind of
|
just to remove it entirely.
|
||||||
issues.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if common.has_extension(inpath, 'png'):
|
extension = common.get_extension(inpath)[1]
|
||||||
shutil.copy(inpath, outpath)
|
if os.path.isdir(outpath):
|
||||||
else:
|
outpath = os.path.join(outpath, os.path.basename(inpath))
|
||||||
with open(inpath) as fp:
|
if extension == 'png':
|
||||||
|
with open(inpath, 'rb') as fp:
|
||||||
|
in_image = Image.open(fp)
|
||||||
|
in_image.save(outpath, "PNG", optimize=True,
|
||||||
|
pnginfo=BLANK_PNG_INFO, icc_profile=None)
|
||||||
|
elif extension == 'jpg' or extension == 'jpeg':
|
||||||
|
with open(inpath, 'rb') as fp:
|
||||||
in_image = Image.open(fp)
|
in_image = Image.open(fp)
|
||||||
data = list(in_image.getdata())
|
data = list(in_image.getdata())
|
||||||
out_image = Image.new(in_image.mode, in_image.size)
|
out_image = Image.new(in_image.mode, in_image.size)
|
||||||
out_image.putdata(data)
|
out_image.putdata(data)
|
||||||
out_image.save(outpath, "JPEG", optimize=True)
|
out_image.save(outpath, "JPEG", optimize=True)
|
||||||
|
else:
|
||||||
|
raise FDroidException(_('Unsupported file type "{extension}" for repo graphic')
|
||||||
|
.format(extension=extension))
|
||||||
|
|
||||||
|
|
||||||
def copy_triple_t_store_metadata(apps):
|
def copy_triple_t_store_metadata(apps):
|
||||||
@ -1512,7 +1523,8 @@ def fill_missing_icon_densities(empty_densities, icon_filename, apk, repo_dir):
|
|||||||
size = dpi_to_px(density)
|
size = dpi_to_px(density)
|
||||||
|
|
||||||
im.thumbnail((size, size), Image.ANTIALIAS)
|
im.thumbnail((size, size), Image.ANTIALIAS)
|
||||||
im.save(icon_path, "PNG")
|
im.save(icon_path, "PNG", optimize=True,
|
||||||
|
pnginfo=BLANK_PNG_INFO, icc_profile=None)
|
||||||
empty_densities.remove(density)
|
empty_densities.remove(density)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.warning("Invalid image file at %s: %s", last_icon_path, e)
|
logging.warning("Invalid image file at %s: %s", last_icon_path, e)
|
||||||
|
Loading…
Reference in New Issue
Block a user