This commit is contained in:
Simon Conseil
2021-07-06 22:02:48 +02:00
parent 1f91e1dee4
commit 68e8e448ef
11 changed files with 29 additions and 18 deletions

View File

@@ -174,7 +174,7 @@ def build(source, destination, debug, verbose, quiet, force, config, theme,
if not quiet: if not quiet:
stats_str = '' stats_str = ''
types = sorted(set(t.rsplit('_',1)[0] for t in stats)) types = sorted(set(t.rsplit('_', 1)[0] for t in stats))
for t in types[:-1]: for t in types[:-1]:
stats_str += '{} and '.format(format_stats(t)) stats_str += '{} and '.format(format_stats(t))
stats_str += '{}'.format(format_stats(types[-1])) stats_str += '{}'.format(format_stats(types[-1]))

View File

@@ -46,7 +46,7 @@ from pilkit.processors import Transpose
from pilkit.utils import save_image from pilkit.utils import save_image
from . import signals, utils from . import signals, utils
from .settings import Status, get_thumb from .settings import Status
try: try:
# Pillow 7.2+ # Pillow 7.2+

View File

@@ -39,4 +39,4 @@ Compatibility with other plugins:
""" """
from .encrypt import register from .encrypt import register # noqa

View File

@@ -35,6 +35,7 @@ from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
backend = default_backend() backend = default_backend()
MAGIC_STRING = b"_e_n_c_r_y_p_t_e_d_" MAGIC_STRING = b"_e_n_c_r_y_p_t_e_d_"
def kdf_gen_key(password: str, salt: str, iters: int) -> bytes: def kdf_gen_key(password: str, salt: str, iters: int) -> bytes:
password = password.encode("utf-8") password = password.encode("utf-8")
salt = salt.encode("utf-8") salt = salt.encode("utf-8")
@@ -48,6 +49,7 @@ def kdf_gen_key(password: str, salt: str, iters: int) -> bytes:
key = kdf.derive(password) key = kdf.derive(password)
return key return key
def dispatchargs(decorated): def dispatchargs(decorated):
def wrapper(args): def wrapper(args):
if args.key is not None: if args.key is not None:
@@ -65,8 +67,9 @@ def dispatchargs(decorated):
return wrapper return wrapper
def encrypt(key: bytes, infile: BinaryIO, outfile: BinaryIO, tag: bytes): def encrypt(key: bytes, infile: BinaryIO, outfile: BinaryIO, tag: bytes):
if len(key) != 128/8: if len(key) != 128 / 8:
raise ValueError("Unsupported key length: %d" % len(key)) raise ValueError("Unsupported key length: %d" % len(key))
aesgcm = AESGCM(key) aesgcm = AESGCM(key)
iv = os.urandom(12) iv = os.urandom(12)
@@ -78,8 +81,9 @@ def encrypt(key: bytes, infile: BinaryIO, outfile: BinaryIO, tag: bytes):
ciphertext.write(iv) ciphertext.write(iv)
ciphertext.write(encrypted) ciphertext.write(encrypted)
def decrypt(key: bytes, infile: BinaryIO, outfile: BinaryIO, tag: bytes): def decrypt(key: bytes, infile: BinaryIO, outfile: BinaryIO, tag: bytes):
if len(key) != 128/8: if len(key) != 128 / 8:
raise ValueError("Unsupported key length: %d" % len(key)) raise ValueError("Unsupported key length: %d" % len(key))
aesgcm = AESGCM(key) aesgcm = AESGCM(key)
ciphertext = infile ciphertext = infile
@@ -95,6 +99,7 @@ def decrypt(key: bytes, infile: BinaryIO, outfile: BinaryIO, tag: bytes):
raise ValueError("Incorrect tag, iv, or corrupted ciphertext") raise ValueError("Incorrect tag, iv, or corrupted ciphertext")
plaintext.write(decrypted) plaintext.write(decrypted)
if __name__ == "__main__": if __name__ == "__main__":
import argparse as ap import argparse as ap
parser = ap.ArgumentParser(description="Encrypt or decrypt using AES-128-GCM") parser = ap.ArgumentParser(description="Encrypt or decrypt using AES-128-GCM")

View File

@@ -70,7 +70,7 @@ def generate_feed(gallery, medias, feed_type=None, feed_url='', nb_items=0):
# item.date.date(), # item.date.date(),
# urlparse(link).path.lstrip('/')), # urlparse(link).path.lstrip('/')),
description='<img src="{}/{}/{}" />'.format(base_url, item.path, description='<img src="{}/{}/{}" />'.format(base_url, item.path,
item.thumbnail), item.thumbnail),
# categories=item.tags if hasattr(item, 'tags') else None, # categories=item.tags if hasattr(item, 'tags') else None,
author_name=getattr(item, 'author', ''), author_name=getattr(item, 'author', ''),
pubdate=item.date or datetime.now(), pubdate=item.date or datetime.now(),

View File

@@ -94,7 +94,7 @@ def filter_nomedia(album, settings=None):
_remove_albums_with_subdirs(album.gallery.albums, [album.path]) _remove_albums_with_subdirs(album.gallery.albums, [album.path])
try: try:
os.rmdir(album.dst_path) os.rmdir(album.dst_path)
except OSError as e: except OSError:
# directory was created and populated with images in a # directory was created and populated with images in a
# previous run => keep it # previous run => keep it
pass pass

View File

@@ -34,7 +34,7 @@ See :ref:`compatibility with the encrypt plugin <compatibility-with-encrypt>`.
import logging import logging
import os import os
import zipfile import zipfile
from os.path import isfile, join, splitext from os.path import isfile, join
from sigal import signals from sigal import signals
from sigal.gallery import Album from sigal.gallery import Album
@@ -42,11 +42,13 @@ from sigal.utils import cached_property
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def _should_generate_album_zip(album): def _should_generate_album_zip(album):
"""Checks whether a `.nozip_gallery` file exists in the album folder""" """Checks whether a `.nozip_gallery` file exists in the album folder"""
nozipgallerypath = os.path.join(album.src_path, ".nozip_gallery") nozipgallerypath = os.path.join(album.src_path, ".nozip_gallery")
return not os.path.isfile(nozipgallerypath) return not os.path.isfile(nozipgallerypath)
def _generate_album_zip(album): def _generate_album_zip(album):
"""Make a ZIP archive with all media files and return its path. """Make a ZIP archive with all media files and return its path.
@@ -81,6 +83,7 @@ def _generate_album_zip(album):
return False return False
def generate_album_zip(album): def generate_album_zip(album):
"""Checks for .nozip_gallery file in album folder. """Checks for .nozip_gallery file in album folder.
If this file exists, no ZIP archive is generated. If this file exists, no ZIP archive is generated.
@@ -98,9 +101,11 @@ def generate_album_zip(album):
return _generate_album_zip(album) return _generate_album_zip(album)
def nozip_gallery_file(album, settings=None): def nozip_gallery_file(album, settings=None):
"""Filesystem based switch to disable ZIP generation for an Album""" """Filesystem based switch to disable ZIP generation for an Album"""
Album.zip = cached_property(generate_album_zip) Album.zip = cached_property(generate_album_zip)
def register(settings): def register(settings):
signals.album_initialized.connect(nozip_gallery_file) signals.album_initialized.connect(nozip_gallery_file)

View File

@@ -28,7 +28,7 @@ import subprocess
from os.path import splitext from os.path import splitext
from . import image, utils from . import image, utils
from .settings import Status, get_thumb from .settings import Status
from .utils import is_valid_html5_video from .utils import is_valid_html5_video
@@ -77,6 +77,7 @@ def video_size(source, converter='ffmpeg'):
x, y = y, x x, y = y, x
return x, y return x, y
def get_resize_options(source, converter, output_size): def get_resize_options(source, converter, output_size):
"""Figure out resize options for video from src and dst sizes. """Figure out resize options for video from src and dst sizes.
@@ -152,10 +153,10 @@ def generate_video(source, outname, settings):
base, dst_ext = splitext(outname) base, dst_ext = splitext(outname)
if dst_ext == src_ext and not resize_opt and not video_always_convert: if dst_ext == src_ext and not resize_opt and not video_always_convert:
logger.debug('For %s, the source and destination extension are the " \ logger.debug('For %s, the source and destination extension are the '
"same, there is no resizing to be done, and " \ 'same, there is no resizing to be done, and '
"video_always_convert is False, so the output is " \ 'video_always_convert is False, so the output is '
" being copied', outname) ' being copied', outname)
shutil.copy(source, outname) shutil.copy(source, outname)
return return
@@ -163,7 +164,7 @@ def generate_video(source, outname, settings):
if second_pass_options: if second_pass_options:
generate_video_pass(converter, source, final_pass_options) generate_video_pass(converter, source, final_pass_options)
final_second_pass_options = _get_empty_if_none_else_variable( final_second_pass_options = _get_empty_if_none_else_variable(
second_pass_options) + resize_opt second_pass_options) + resize_opt
generate_video_pass(converter, source, generate_video_pass(converter, source,
final_second_pass_options, outname) final_second_pass_options, outname)
else: else:

View File

@@ -20,6 +20,7 @@ def get_key_tag(settings):
tag = options["gcm_tag"].encode("utf-8") tag = options["gcm_tag"].encode("utf-8")
return (key, tag) return (key, tag)
def test_encrypt(settings, tmpdir, disconnect_signals): def test_encrypt(settings, tmpdir, disconnect_signals):
settings['destination'] = str(tmpdir) settings['destination'] = str(tmpdir)
if "sigal.plugins.encrypt" not in settings["plugins"]: if "sigal.plugins.encrypt" not in settings["plugins"]:
@@ -63,7 +64,7 @@ def test_encrypt(settings, tmpdir, disconnect_signals):
] ]
if settings["keep_orig"]: if settings["keep_orig"]:
encryptedImages.append(os.path.join(settings["destination"], encryptedImages.append(os.path.join(settings["destination"],
media.path, media.big)) media.path, media.big))
# check if images are encrypted by trying to decrypt # check if images are encrypted by trying to decrypt
for image in encryptedImages: for image in encryptedImages:
@@ -79,6 +80,6 @@ def test_encrypt(settings, tmpdir, disconnect_signals):
# check keycheck file # check keycheck file
with open(os.path.join(settings["destination"], with open(os.path.join(settings["destination"],
'static', "keycheck.txt"), "rb") as infile: 'static', "keycheck.txt"), "rb") as infile:
with BytesIO() as outfile: with BytesIO() as outfile:
endec.decrypt(key, infile, outfile, tag) endec.decrypt(key, infile, outfile, tag)

View File

@@ -5,7 +5,7 @@ import pytest
from sigal.gallery import Video from sigal.gallery import Video
from sigal.settings import Status, create_settings from sigal.settings import Status, create_settings
from sigal.video import (generate_thumbnail, generate_video, process_video, from sigal.video import (generate_thumbnail, generate_video, process_video,
video_size, get_resize_options, generate_video_pass) video_size)
from unittest.mock import patch from unittest.mock import patch
CURRENT_DIR = os.path.dirname(__file__) CURRENT_DIR = os.path.dirname(__file__)

View File

@@ -1,4 +1,3 @@
import glob
import os import os
import zipfile import zipfile