diff options
Diffstat (limited to 'store')
-rw-r--r-- | store/admin.py | 43 | ||||
-rw-r--r-- | store/api.py | 43 | ||||
-rw-r--r-- | store/authdecorators.py | 4 | ||||
-rw-r--r-- | store/management/commands/expire-downloads.py | 4 | ||||
-rw-r--r-- | store/migrations/0001_initial.py | 9 | ||||
-rw-r--r-- | store/migrations/0002_alter_category_order.py | 18 | ||||
-rw-r--r-- | store/models.py | 14 | ||||
-rw-r--r-- | store/tags.py | 20 | ||||
-rw-r--r-- | store/utilities.py | 77 |
9 files changed, 118 insertions, 114 deletions
diff --git a/store/admin.py b/store/admin.py index 910f3fb..389bb87 100644 --- a/store/admin.py +++ b/store/admin.py @@ -30,15 +30,14 @@ ## ############################################################################# -import StringIO +import io from PIL import Image, ImageChops from django import forms from django.contrib import admin -from django.utils.translation import ugettext as _ -from django.utils.translation import ugettext_lazy from django.core.files.uploadedfile import InMemoryUploadedFile from ordered_model.admin import OrderedModelAdmin +from django.utils.safestring import mark_safe from store.models import * from store.utilities import parseAndValidatePackageMetadata, writeTempIcon, makeTagList @@ -68,10 +67,11 @@ class CategoryAdminForm(forms.ModelForm): im = Image.open(cleaned_data['icon']) size = (settings.ICON_SIZE_X, settings.ICON_SIZE_Y) im.thumbnail(size, Image.ANTIALIAS) - imagefile = StringIO.StringIO() + imagefile = io.BytesIO() im.save(imagefile, format='png') + length = imagefile.tell() imagefile.seek(0) - cleaned_data['icon'] = InMemoryUploadedFile(imagefile, 'icon', "icon.png", 'image/png', imagefile.len, None) + cleaned_data['icon'] = InMemoryUploadedFile(imagefile, 'icon', "icon.png", 'image/png', length, None) return cleaned_data class CategoryAdmin(OrderedModelAdmin): @@ -85,16 +85,15 @@ class CategoryAdmin(OrderedModelAdmin): def name(self, obj): # just to forbid sorting by name return obj.name - name.short_description = ugettext_lazy('Item caption') + name.short_description = u'Item caption' def icon_image(self, obj): prefix = settings.URL_PREFIX image_request = prefix + "/category/icon?id=%s" % (obj.id) - html = u'<img width=%s height=%s src="%s" />' % (settings.ICON_SIZE_X, settings.ICON_SIZE_Y, image_request) - return html + html = '<img width=%s height=%s src="%s" />' % (settings.ICON_SIZE_X, settings.ICON_SIZE_Y, image_request) + return mark_safe(html) - icon_image.allow_tags = True - icon_image.short_description = ugettext_lazy('Category icon') + icon_image.short_description = u'Category icon' class AppAdminForm(forms.ModelForm): @@ -113,7 +112,7 @@ class AppAdminForm(forms.ModelForm): try: pkgdata = parseAndValidatePackageMetadata(package_file) except Exception as error: - raise forms.ValidationError(_('Validation error: %s' % str(error))) + raise forms.ValidationError('Validation error: %s' % str(error)) self.appId = pkgdata['info']['id'] self.name = pkgdata['storeName'] @@ -123,27 +122,27 @@ class AppAdminForm(forms.ModelForm): # check if this really is an update if hasattr(self, 'instance') and self.instance.appid: if self.appId != self.instance.appid: - raise forms.ValidationError(_('Validation error: an update cannot change the ' - 'application id, tried to change from %s to %s' % - (self.instance.appid, self.appId))) + raise forms.ValidationError('Validation error: an update cannot change the ' + 'application id, tried to change from %s to %s' % + (self.instance.appid, self.appId)) elif self.architecture != self.instance.architecture: - raise forms.ValidationError(_('Validation error: an update cannot change the ' - 'application architecture from %s to %s' % - (self.instance.architecture, self.architecture))) + raise forms.ValidationError('Validation error: an update cannot change the ' + 'application architecture from %s to %s' % + (self.instance.architecture, self.architecture)) else: try: if App.objects.get(appid__exact=self.appId, architecture__exact=self.architecture, tags_hash__exact=self.tags_hash): - raise forms.ValidationError(_('Validation error: another application with id' - ' %s , tags %s and architecture %s already ' - 'exists' % (str(self.appId), str(self.tags_hash), - str(self.architecture)))) + raise forms.ValidationError('Validation error: another application with id' + ' %s , tags %s and architecture %s already ' + 'exists' % (str(self.appId), str(self.tags_hash), + str(self.architecture))) except App.DoesNotExist: pass # write icon into file to serve statically success, error = writeTempIcon(self.appId, self.architecture, self.tags_hash, pkgdata['icon']) if not success: - raise forms.ValidationError(_(error)) + raise forms.ValidationError(error) return cleaned_data diff --git a/store/api.py b/store/api.py index 9444b0b..b617e34 100644 --- a/store/api.py +++ b/store/api.py @@ -33,6 +33,7 @@ import os import shutil import hashlib +import logging from django.conf import settings from django.db.models import Q, Count @@ -89,7 +90,6 @@ def hello(request): else: request.session['architecture'] = '' - request.session['pkgversions'] = range(1, version + 1) return JsonResponse({'status': status}) @@ -120,7 +120,7 @@ def login(request): def logout(request): status = 'ok' - if not request.user.is_authenticated(): + if not request.user.is_authenticated: status = 'failed' logout(request) @@ -201,12 +201,7 @@ def appList(request): if 'architecture' in request.session: archlist.append(request.session['architecture']) - versionlist = [1] - if 'pkgversions' in request.session: - versionlist = request.session['pkgversions'] - apps = apps.filter(architecture__in=archlist) - apps = apps.filter(pkgformat__in=versionlist) #Tag filtering #There is no search by version distance yet - this must be fixed @@ -261,13 +256,9 @@ def appDescription(request): archlist = ['All', ] if 'architecture' in request.session: archlist.append(request.session['architecture']) - versionlist = [1] - if 'pkgversions' in request.session: - versionlist = request.session['pkgversions'] appId = getRequestDictionary(request)['id'] try: app = App.objects.filter(appid__exact = appId, architecture__in = archlist).order_by('architecture','tags_hash') - app = app.filter(pkgformat__in=versionlist) #Tag filtering #There is no search by version distance yet - this must be fixed if 'tag' in request.session: @@ -285,7 +276,7 @@ def appIconNew(request, path): path=path.replace('/', '_').replace('\\', '_').replace(':', 'x3A').replace(',', 'x2C') + '.png' try: response = HttpResponse(content_type='image/png') - with open(iconPath() + path, 'rb') as pkg: + with open(os.path.join(settings.MEDIA_ROOT, iconPath(), path), 'rb') as pkg: response.write(pkg.read()) response['Content-Length'] = pkg.tell() return response @@ -299,22 +290,20 @@ def appIcon(request): archlist.append(normalizeArch(dictionary['architecture'])) elif 'architecture' in request.session: archlist.append(request.session['architecture']) - versionlist = [1] - if 'pkgversions' in request.session: - versionlist = request.session['pkgversions'] appId = dictionary['id'] try: - app = App.objects.filter(appid__exact = appId, architecture__in = archlist).order_by('architecture','tags_hash') - app = app.filter(pkgformat__in=versionlist) + apps = App.objects.filter(appid__exact = appId, architecture__in = archlist).order_by('architecture','tags_hash') #Tag filtering #There is no search by version distance yet - this must be fixed if 'tag' in request.session: tags = SoftwareTagList() tags.parse(request.session['tag']) - app_ids = [x.id for x in app if x.is_tagmatching(tags.list())] - app = App.objects.filter(id__in=app_ids) - app = app.last() - with open(iconPath(app.appid, app.architecture, app.tags_hash), 'rb') as iconPng: + app_ids = [x.id for x in apps if x.is_tagmatching(tags.list())] + apps = App.objects.filter(id__in=app_ids) + app = apps.last() + path = iconPath(app.appid, app.architecture, app.tags_hash) + path = os.path.join(settings.MEDIA_ROOT, path) + with open(path, 'rb') as iconPng: response = HttpResponse(content_type='image/png') response.write(iconPng.read()) return response @@ -323,14 +312,11 @@ def appIcon(request): def appPurchase(request): - if not request.user.is_authenticated(): + if not request.user.is_authenticated: return HttpResponseForbidden('no login') archlist = ['All', ] if 'architecture' in request.session: archlist.append(request.session['architecture']) - versionlist = [1] - if 'pkgversions' in request.session: - versionlist = request.session['pkgversions'] try: deviceId = str(getRequestDictionary(request).get("device_id", "")) @@ -346,7 +332,6 @@ def appPurchase(request): app = App.objects.filter(id__exact = getRequestDictionary(request)['purchaseId'], architecture__in=archlist).order_by('architecture','tags_hash') else: raise ValidationError('id or purchaseId parameter required') - app = app.filter(pkgformat__in=versionlist) #Tag filtering #There is no search by version distance yet - this must be fixed if 'tag' in request.session: @@ -356,7 +341,7 @@ def appPurchase(request): app = App.objects.filter(id__in=app_ids) app = app.last() - fromFilePath = packagePath(app.appid, app.architecture, app.tags_hash) + fromFilePath = os.path.join(settings.MEDIA_ROOT, packagePath(app.appid, app.architecture, app.tags_hash)) # we should not use obvious names here, but just hash the string. # this would be a nightmare to debug though and this is a development server :) @@ -423,7 +408,7 @@ def categoryIcon(request): try: if categoryId != '-1': category = Category.objects.filter(id__exact = categoryId)[0] - filename = iconPath() + "category_" + str(category.id) + ".png" + filename = os.path.join(settings.MEDIA_ROOT, iconPath(), "category_" + str(category.id) + ".png") else: from django.contrib.staticfiles import finders filename = finders.find('img/category_All.png') @@ -439,7 +424,7 @@ def categoryIcon(request): # |Error| # | | # +-----+ - emptyPng = "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x01\x03\x00\x00\x00I\xb4\xe8\xb7\x00\x00\x00\x06PLTE\x00\x00\x00\x00\x00\x00\xa5\x67\xb9\xcf\x00\x00\x00\x01tRNS\x00@\xe6\xd8f\x00\x00\x00\x33IDAT\x08\xd7\x63\xf8\x0f\x04\x0c\x0d\x0c\x0c\x8c\x44\x13\x7f\x40\xc4\x01\x10\x71\xb0\xf4\x5c\x2c\xc3\xcf\x36\xc1\x44\x86\x83\x2c\x82\x8e\x48\xc4\x5f\x16\x3e\x47\xd2\x0c\xc5\x46\x80\x9c\x06\x00\xa4\xe5\x1d\xb4\x8e\xae\xe8\x43\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82" + emptyPng = b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x01\x03\x00\x00\x00I\xb4\xe8\xb7\x00\x00\x00\x06PLTE\x00\x00\x00\x00\x00\x00\xa5\x67\xb9\xcf\x00\x00\x00\x01tRNS\x00@\xe6\xd8f\x00\x00\x00\x33IDAT\x08\xd7\x63\xf8\x0f\x04\x0c\x0d\x0c\x0c\x8c\x44\x13\x7f\x40\xc4\x01\x10\x71\xb0\xf4\x5c\x2c\xc3\xcf\x36\xc1\x44\x86\x83\x2c\x82\x8e\x48\xc4\x5f\x16\x3e\x47\xd2\x0c\xc5\x46\x80\x9c\x06\x00\xa4\xe5\x1d\xb4\x8e\xae\xe8\x43\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82" response.write(emptyPng) return response diff --git a/store/authdecorators.py b/store/authdecorators.py index 2a4119c..a4307ff 100644 --- a/store/authdecorators.py +++ b/store/authdecorators.py @@ -60,7 +60,7 @@ def view_or_basicauth(view, request, test_func, realm="", *args, **kwargs): # NOTE: We are only support basic authentication for now. # if auth[0].lower() == "basic": - uname, passwd = base64.b64decode(auth[1]).split(':') + uname, passwd = base64.b64decode(auth[1].encode('utf-8')).decode('utf-8').split(':') user = authenticate(username=uname, password=passwd) if user is not None: if user.is_active: @@ -114,7 +114,7 @@ def logged_in_or_basicauth(realm=""): def view_decorator(func): def wrapper(request, *args, **kwargs): return view_or_basicauth(func, request, - lambda u: u.is_authenticated(), + lambda u: u.is_authenticated, realm, *args, **kwargs) return wrapper diff --git a/store/management/commands/expire-downloads.py b/store/management/commands/expire-downloads.py index 94b0d24..012182e 100644 --- a/store/management/commands/expire-downloads.py +++ b/store/management/commands/expire-downloads.py @@ -39,7 +39,7 @@ from django.conf import settings from store.utilities import downloadPath class Command(BaseCommand): - help = 'Expires all downloads that are older than 10 minutes' + help = 'Expires all downloads that are older than APPSTORE_DOWNLOAD_EXPIRY minutes' def handle(self, *args, **options): self.stdout.write('Removing expired download packages') @@ -50,7 +50,7 @@ class Command(BaseCommand): for pkg in os.listdir(pkgPath): t = os.path.getmtime(pkgPath + pkg) age = time.time() - t - if age > (10 * 60): + if age > (int(settings.APPSTORE_DOWNLOAD_EXPIRY) * 60): os.remove(pkgPath + pkg) self.stdout.write(' -> %s (age: %s seconds)' % (pkg, int(age))) diff --git a/store/migrations/0001_initial.py b/store/migrations/0001_initial.py index 80d154c..2bb3457 100644 --- a/store/migrations/0001_initial.py +++ b/store/migrations/0001_initial.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.11.27 on 2020-08-14 17:24 ############################################################################# ## ## Copyright (C) 2020 Luxoft Sweden AB @@ -32,7 +31,7 @@ ## ############################################################################# -# Generated by Django 1.11.27 on 2020-07-22 16:39 +# Generated by Django 1.11.27 on 2020-10-30 13:46 from __future__ import unicode_literals from django.conf import settings @@ -62,9 +61,9 @@ class Migration(migrations.Migration): ('description', models.TextField()), ('dateAdded', models.DateField(auto_now_add=True)), ('dateModified', models.DateField(auto_now=True)), - ('tags_hash', models.CharField(default=b'', max_length=4096)), - ('architecture', models.CharField(default=b'All', max_length=20)), - ('version', models.CharField(default=b'0.0.0', max_length=20)), + ('tags_hash', models.CharField(default='', max_length=4096)), + ('architecture', models.CharField(default='All', max_length=20)), + ('version', models.CharField(default='0.0.0', max_length=20)), ('pkgformat', models.IntegerField()), ], ), diff --git a/store/migrations/0002_alter_category_order.py b/store/migrations/0002_alter_category_order.py new file mode 100644 index 0000000..e13175c --- /dev/null +++ b/store/migrations/0002_alter_category_order.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.6 on 2023-06-26 19:18 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('store', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='category', + name='order', + field=models.PositiveIntegerField(db_index=True, editable=False, verbose_name='order'), + ), + ] diff --git a/store/models.py b/store/models.py index 7e8751a..ff8ab0c 100644 --- a/store/models.py +++ b/store/models.py @@ -45,7 +45,7 @@ from store.tags import SoftwareTag def category_file_name(instance, filename): # filename parameter is unused. See django documentation for details: # https://docs.djangoproject.com/en/1.11/ref/models/fields/#django.db.models.FileField.upload_to - return settings.MEDIA_ROOT + "icons/category_" + str(instance.id) + ".png" + return "icons/category_" + str(instance.id) + ".png" class OverwriteStorage(FileSystemStorage): def get_available_name(self, name, max_length=None): @@ -63,6 +63,9 @@ class Category(OrderedModel): def __unicode__(self): return self.name + def __str__(self): + return self.name + def save(self, *args, **kwargs): if self.id is None: # This is a django hack. When category icon is saved and then later accessed, @@ -77,13 +80,16 @@ class Category(OrderedModel): super(Category, self).save(*args, **kwargs) class Vendor(models.Model): - user = models.ForeignKey(User, primary_key = False) + user = models.ForeignKey(User, primary_key = False, on_delete = models.CASCADE) name = models.CharField(max_length = 200) certificate = models.TextField(max_length = 8000) def __unicode__(self): return self.name + def __str__(self): + return self.name + class Tag(models.Model): negative = models.BooleanField(default=False) name = models.CharField(max_length=200) @@ -106,8 +112,8 @@ class App(models.Model): appid = models.CharField(max_length=200) name = models.CharField(max_length=200) file = models.FileField(upload_to=content_file_name, storage=OverwriteStorage()) - vendor = models.ForeignKey(Vendor) - category = models.ForeignKey(Category) + vendor = models.ForeignKey(Vendor, on_delete = models.CASCADE) + category = models.ForeignKey(Category, on_delete = models.CASCADE) briefDescription = models.TextField() description = models.TextField() dateAdded = models.DateField(auto_now_add=True) diff --git a/store/tags.py b/store/tags.py index e906684..da09803 100644 --- a/store/tags.py +++ b/store/tags.py @@ -79,7 +79,7 @@ class SoftwareTag: """ Takes tag and parses it. If it can't parse - raises exception of invalid value :type tag: str """ - if not isinstance(tag, (str, unicode)): + if not isinstance(tag, str): raise BaseException("Invalid input data-type") if not validateTag(tag): raise BaseException("Malformed tag") @@ -121,7 +121,7 @@ class SoftwareTagList: def __str__(self): lst = list() - for _, value in self.taglist.items(): + for _, value in list(self.taglist.items()): lst += [str(i) for i in value] lst.sort() return ",".join(lst) @@ -168,7 +168,7 @@ class SoftwareTagList: def list(self): lst = list() - for _, value in self.taglist.items(): + for _, value in list(self.taglist.items()): for i in value: lst.append(i) return lst @@ -188,13 +188,13 @@ class TestSoftwareTagMethods(unittest.TestCase): self.assertTrue(tag.has_version()) tag = SoftwareTag('Qt') self.assertFalse(tag.has_version()) - with self.assertRaisesRegexp(BaseException, "Malformed tag"): + with self.assertRaisesRegex(BaseException, "Malformed tag"): SoftwareTag('фыва') - with self.assertRaisesRegexp(BaseException, "Malformed tag"): + with self.assertRaisesRegex(BaseException, "Malformed tag"): SoftwareTag('фыва:5.1') - with self.assertRaisesRegexp(BaseException, "Malformed tag"): + with self.assertRaisesRegex(BaseException, "Malformed tag"): SoftwareTag('qt.1:5.1') - with self.assertRaisesRegexp(BaseException, "Invalid input data-type"): + with self.assertRaisesRegex(BaseException, "Invalid input data-type"): SoftwareTag(1) def test_tag_match(self): @@ -227,11 +227,11 @@ class TestSoftwareTagListMethods(unittest.TestCase): def test_append_invalid(self): lst = SoftwareTagList() - with self.assertRaisesRegexp(BaseException, "Malformed tag"): + with self.assertRaisesRegex(BaseException, "Malformed tag"): self.assertFalse(lst.append(SoftwareTag('qt:1:1'))) # Invalid version - with self.assertRaisesRegexp(BaseException, "Malformed tag"): + with self.assertRaisesRegex(BaseException, "Malformed tag"): self.assertFalse(lst.append(SoftwareTag('фыва'))) # Non-ascii - with self.assertRaisesRegexp(BaseException, "Malformed tag"): + with self.assertRaisesRegex(BaseException, "Malformed tag"): self.assertFalse(lst.append(SoftwareTag(''))) # empty tag is not valid def test_append_valid(self): diff --git a/store/utilities.py b/store/utilities.py index 06151bb..1a283e5 100644 --- a/store/utilities.py +++ b/store/utilities.py @@ -70,28 +70,29 @@ def getRequestDictionary(request): return request.GET def packagePath(appId=None, architecture=None, tags=None): - path = settings.MEDIA_ROOT + 'packages/' + path = "packages" ## os.path.join(settings.MEDIA_ROOT, 'packages/') if tags is None: tags = "" if (appId is not None) and (architecture is not None): - path = path + '_'.join([appId, architecture, tags]).replace('/', '_').\ - replace('\\', '_').replace(':', 'x3A').replace(',', 'x2C') + path = os.path.join(path, '_'.join([appId, architecture, tags]).replace('/', '_').\ + replace('\\', '_').replace(':', 'x3A').replace(',', 'x2C')) return path def iconPath(appId=None, architecture=None, tags=None): - path = settings.MEDIA_ROOT + 'icons/' + path = "icons" ## os.path.join(settings.MEDIA_ROOT, 'icons/') if tags is None: tags = "" if (appId is not None) and (architecture is not None): - return path + '_'.join([appId, architecture, tags]).replace('/', '_').\ - replace('\\', '_').replace(':', 'x3A').replace(',', 'x2C') + '.png' + return os.path.join(path, '_'.join([appId, architecture, tags]).replace('/', '_').\ + replace('\\', '_').replace(':', 'x3A').replace(',', 'x2C') + '.png') return path def writeTempIcon(appId, architecture, tags, icon): try: - if not os.path.exists(iconPath()): - os.makedirs(iconPath()) - tempicon = open(iconPath(appId, architecture, tags), 'w') + path = os.path.join(settings.MEDIA_ROOT, iconPath()) + if not os.path.exists(path): + os.makedirs(path) + tempicon = open(os.path.join(settings.MEDIA_ROOT, iconPath(appId, architecture, tags)), 'wb') tempicon.write(icon) tempicon.flush() tempicon.close() @@ -101,39 +102,35 @@ def writeTempIcon(appId, architecture, tags, icon): str(error) def downloadPath(): - return settings.MEDIA_ROOT + 'downloads/' + return os.path.join(settings.MEDIA_ROOT, 'downloads/') -def isValidDnsName(dnsName, errorList): - # see also in AM: src/common-lib/utilities.cpp / isValidDnsName() +def isValidFilesystemName(name, errorList): + # see also in AM: src/common-lib/utilities.cpp / validateForFilesystemUsage try: - # this is not based on any RFC, but we want to make sure that this id is usable as filesystem - # name. So in order to support FAT (SD-Cards), we need to keep the path < 256 characters + # we need to make sure that we can use the name as directory in a filesystem and inode names + # are limited to 255 characters in Linux. We need to subtract a safety margin for prefixes + # or suffixes though: - if len(dnsName) > 200: - raise Exception('too long - the maximum length is 200 characters') + if not name: + raise Exception('must not be empty') - # we require at least 3 parts: tld.company-name.application-name - # this make it easier for humans to identify apps by id. + if len(name) > 150: + raise Exception('the maximum length is 150 characters') - labels = dnsName.split('.') - if len(labels) < 3: - raise Exception('wrong format - needs to be in reverse-DNS notation and consist of at least three parts separated by .') + # all characters need to be ASCII minus any filesystem special characters: + spaceOnly = True + forbiddenChars = '<>:"/\\|?*' + for i, c in enumerate(name): + if (ord(c) < 0x20) or (ord(c) > 0x7f) or (c in forbiddenChars): + raise Exception(f'must consist of printable ASCII characters only, except any of \'{forbiddenChars}\'') - # standard domain name requirements from the RFCs 1035 and 1123 + if spaceOnly: + spaceOnly = (c == ' ') - for label in labels: - if 0 >= len(label) > 63: - raise Exception('wrong format - each part of the name needs to at least 1 and at most 63 characters') - - for i, c in enumerate(label): - isAlpha = (c >= '0' and c <= '9') or (c >= 'a' and c <= 'z'); - isDash = (c == '-'); - isInMiddle = (i > 0) and (i < (len(label) - 1)); - - if not (isAlpha or (isDash and isInMiddle)): - raise Exception('invalid characters - only [a-z0-9-] are allowed (and '-' cannot be the first or last character)') + if spaceOnly: + raise Exception('must not consist of only white-space characters') return True @@ -141,7 +138,6 @@ def isValidDnsName(dnsName, errorList): errorList[0] = str(error) return False - def verifySignature(signaturePkcs7, hash, chainOfTrust): # see also in AM: src/crypto-lib/signature.cpp / Signature::verify() @@ -256,7 +252,7 @@ def parsePackageMetadata(packageFile): raise Exception('the first file in the package is not --PACKAGE-HEADER--, but %s' % entry.name) if entry.name.startswith('--PACKAGE-FOOTER--'): - footerContents += contents + footerContents += contents.decode('utf-8') foundFooter = True elif foundFooter: @@ -264,10 +260,11 @@ def parsePackageMetadata(packageFile): if not entry.name.startswith('--PACKAGE-'): addToDigest1 = '%s/%s/' % ('D' if entry.isdir() else 'F', 0 if entry.isdir() else entry.size) + addToDigest1 = addToDigest1.encode('utf-8') entryName = entry.name if entry.isdir() and entryName.endswith('/'): entryName = entryName[:-1] - addToDigest2 = unicode(entryName, 'utf-8').encode('utf-8') + addToDigest2 = str(entryName).encode('utf-8') if entry.isfile(): digest.update(contents) @@ -380,7 +377,7 @@ def parseAndValidatePackageMetadata(packageFile, certificates = []): 'icon': [], 'digest': [] } - for part in partFields.keys(): + for part in list(partFields.keys()): if not part in pkgdata: raise Exception('package metadata is missing the %s part' % part) data = pkgdata[part] @@ -393,7 +390,7 @@ def parseAndValidatePackageMetadata(packageFile, certificates = []): raise Exception('the id fields in --PACKAGE-HEADER-- and info.yaml are different: %s vs. %s' % (pkgdata['header'][packageIdKey], pkgdata['info']['id'])) error = [''] - if not isValidDnsName(pkgdata['info']['id'], error): + if not isValidFilesystemName(pkgdata['info']['id'], error): raise Exception('invalid id: %s' % error[0]) if pkgdata['header']['diskSpaceUsed'] <= 0: @@ -408,7 +405,7 @@ def parseAndValidatePackageMetadata(packageFile, certificates = []): elif 'en_US' in pkgdata['info']['name']: name = pkgdata['info']['name']['en_US'] elif len(pkgdata['info']['name']) > 0: - name = pkgdata['info']['name'].values()[0] + name = list(pkgdata['info']['name'].values())[0] if not name: raise Exception('could not deduce a suitable package name from the info part') @@ -456,7 +453,7 @@ def addFileToPackage(sourcePackageFile, destinationPackageFile, fileName, fileCo entry = dst.gettarinfo(fileobj = tmp, arcname = fileName) entry.uid = entry.gid = 0 entry.uname = entry.gname = '' - entry.mode = 0400 + entry.mode = 0o400 dst.addfile(entry, fileobj = tmp) dst.close() |