export_import: invalid bundle (#88068)

This commit is contained in:
Lauréline Guérin 2024-03-14 09:54:48 +01:00
parent 0ea056dcd5
commit c4bcf4b85a
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
2 changed files with 58 additions and 18 deletions

View File

@ -28,6 +28,7 @@ from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from chrono.agendas.models import Agenda, Category, EventsType, Resource, UnavailabilityCalendar
from chrono.api.utils import APIError
from chrono.apps.export_import.models import Application, ApplicationElement
from chrono.manager.utils import import_site
@ -213,25 +214,32 @@ class BundleImport(GenericAPIView):
def put(self, request, *args, **kwargs):
tar_io = io.BytesIO(request.read())
components = {}
with tarfile.open(fileobj=tar_io) as tar:
manifest = json.loads(tar.extractfile('manifest.json').read().decode())
self.application = Application.update_or_create_from_manifest(
manifest,
tar,
editable=not self.install,
)
for element in manifest.get('elements'):
component_type = element['type']
if component_type not in klasses or element['type'] == 'roles':
continue
component_type = klasses_translation.get(component_type, component_type)
if component_type not in components:
components[component_type] = []
component_content = (
tar.extractfile('%s/%s' % (element['type'], element['slug'])).read().decode()
try:
with tarfile.open(fileobj=tar_io) as tar:
try:
manifest = json.loads(tar.extractfile('manifest.json').read().decode())
except KeyError:
raise APIError(_('Invalid tar file, missing manifest'))
self.application = Application.update_or_create_from_manifest(
manifest,
tar,
editable=not self.install,
)
components[component_type].append(json.loads(component_content).get('data'))
for element in manifest.get('elements'):
component_type = element['type']
if component_type not in klasses or element['type'] == 'roles':
continue
component_type = klasses_translation.get(component_type, component_type)
if component_type not in components:
components[component_type] = []
component_content = (
tar.extractfile('%s/%s' % (element['type'], element['slug'])).read().decode()
)
components[component_type].append(json.loads(component_content).get('data'))
except tarfile.TarError:
raise APIError(_('Invalid tar file'))
# init cache of application elements, from manifest
self.application_elements = set()
# import agendas

View File

@ -525,6 +525,22 @@ def test_bundle_import(app, user):
is False
)
# bad file format
resp = app.put('/api/export-import/bundle-import/', b'garbage')
assert resp.json['err']
assert resp.json['err_desc'] == 'Invalid tar file'
# missing manifest
tar_io = io.BytesIO()
with tarfile.open(mode='w', fileobj=tar_io) as tar:
foo_fd = io.BytesIO(json.dumps({'foo': 'bar'}, indent=2).encode())
tarinfo = tarfile.TarInfo('foo.json')
tarinfo.size = len(foo_fd.getvalue())
tar.addfile(tarinfo, fileobj=foo_fd)
resp = app.put('/api/export-import/bundle-import/', tar_io.getvalue())
assert resp.json['err']
assert resp.json['err_desc'] == 'Invalid tar file, missing manifest'
def test_bundle_declare(app, user):
app.authorization = ('Basic', ('john.doe', 'password'))
@ -563,6 +579,22 @@ def test_bundle_declare(app, user):
assert application.visible is True
assert ApplicationElement.objects.count() == 4 # category, events_type, unavailability_calendar, resource
# bad file format
resp = app.put('/api/export-import/bundle-declare/', b'garbage')
assert resp.json['err']
assert resp.json['err_desc'] == 'Invalid tar file'
# missing manifest
tar_io = io.BytesIO()
with tarfile.open(mode='w', fileobj=tar_io) as tar:
foo_fd = io.BytesIO(json.dumps({'foo': 'bar'}, indent=2).encode())
tarinfo = tarfile.TarInfo('foo.json')
tarinfo.size = len(foo_fd.getvalue())
tar.addfile(tarinfo, fileobj=foo_fd)
resp = app.put('/api/export-import/bundle-declare/', tar_io.getvalue())
assert resp.json['err']
assert resp.json['err_desc'] == 'Invalid tar file, missing manifest'
def test_bundle_unlink(app, user, bundle):
app.authorization = ('Basic', ('john.doe', 'password'))