increased security by encrypting with own key, different on each instalation

This commit is contained in:
Adolfo Gómez García 2022-10-27 14:46:34 +02:00
parent ad269b3c28
commit 7bd0d571e6
No known key found for this signature in database
GPG Key ID: DD1ABF20724CDA23
2 changed files with 81 additions and 40 deletions

View File

@ -40,13 +40,14 @@ import logging
from collections import abc from collections import abc
from django.utils.translation import get_language, ugettext as _, ugettext_noop from django.utils.translation import get_language, ugettext as _, ugettext_noop
from django.conf import settings
from uds.core.managers import cryptoManager from uds.core.managers import cryptoManager
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
UDSB = b'udsprotect' UDSB = b'udsprotect' # UDS base key, old
UDSK = settings.SECRET_KEY[8:24].encode() # UDS key, new
class gui: class gui:
""" """
@ -1080,8 +1081,9 @@ class UserInterface(metaclass=UserInterfaceType):
# logger.debug('Serializing value {0}'.format(v.value)) # logger.debug('Serializing value {0}'.format(v.value))
val = b'\001' + pickle.dumps(v.value, protocol=0) val = b'\001' + pickle.dumps(v.value, protocol=0)
elif v.isType(gui.InfoField.PASSWORD_TYPE): elif v.isType(gui.InfoField.PASSWORD_TYPE):
val = b'\004' + cryptoManager().AESCrypt( # Old \004 field type is not used anymore, is for old "udsprotect" encryption
v.value.encode('utf8'), UDSB, True val = b'\005' + cryptoManager().AESCrypt(
v.value.encode('utf8'), UDSK, True
) )
elif v.isType(gui.InputField.NUMERIC_TYPE): elif v.isType(gui.InputField.NUMERIC_TYPE):
val = str(int(v.num())).encode('utf8') val = str(int(v.num())).encode('utf8')
@ -1132,6 +1134,8 @@ class UserInterface(metaclass=UserInterfaceType):
val = pickle.loads(v[1:]) val = pickle.loads(v[1:])
elif v and v[0] == 4: elif v and v[0] == 4:
val = cryptoManager().AESDecrypt(v[1:], UDSB, True).decode() val = cryptoManager().AESDecrypt(v[1:], UDSB, True).decode()
elif v and v[0] == 5:
val = cryptoManager().AESDecrypt(v[1:], UDSK, True).decode()
else: else:
val = v val = v
# Ensure "legacy bytes" values are loaded correctly as unicode # Ensure "legacy bytes" values are loaded correctly as unicode

View File

@ -30,12 +30,14 @@
""" """
Author: Adolfo Gómez, dkmaster at dkmon dot com Author: Adolfo Gómez, dkmaster at dkmon dot com
""" """
from functools import reduce
import logging import logging
import operator
import typing import typing
import csv
import yaml import yaml
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django.db.models import Q
from uds import models from uds import models
@ -195,12 +197,46 @@ def osmanager_exporter(osmanager: models.OSManager) -> typing.Dict[str, typing.A
o = managed_object_exporter(osmanager) o = managed_object_exporter(osmanager)
return o return o
def calendar_exporter(calendar: models.Calendar) -> typing.Dict[str, typing.Any]:
"""
Exports a calendar to a dict
"""
c = uuid_object_exporter(calendar)
c.update(
{
'name': calendar.name,
'comments': calendar.comments,
'modified': calendar.modified,
}
)
return c
def calendar_rule_exporter(calendar_rule: models.CalendarRule) -> typing.Dict[str, typing.Any]:
"""
Exports a calendar rule to a dict
"""
c = uuid_object_exporter(calendar_rule)
c.update(
{
'calendar': calendar_rule.calendar.uuid,
'name': calendar_rule.name,
'comments': calendar_rule.comments,
'start': calendar_rule.start,
'end': calendar_rule.end,
'frequency': calendar_rule.frequency,
'interval': calendar_rule.interval,
'duration': calendar_rule.duration,
'duration_unit': calendar_rule.duration_unit,
}
)
return c
class Command(BaseCommand): class Command(BaseCommand):
help = 'Export entities from UDS to be imported in another UDS instance' help = 'Export entities from UDS to be imported in another UDS instance'
VALID_ENTITIES: typing.Mapping[str, typing.Callable[[], str]] VALID_ENTITIES: typing.Mapping[str, typing.Callable[[], str]]
verbose: bool = True verbose: bool = True
filter_args: typing.List[typing.Tuple[str, str]] = []
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@ -234,21 +270,21 @@ class Command(BaseCommand):
help='Output file name. Defaults to /tmp/export.yaml', help='Output file name. Defaults to /tmp/export.yaml',
) )
# Filter ALL entities by name # Filter ALL entities by name, multiple names can be specified
parser.add_argument( parser.add_argument(
'--filter-name', '--filter-name',
action='store', action='append',
dest='filter_name', dest='filter_name',
default=None, default=[],
help='Filter ALL entities by name', help='Filter ALL entities by name',
) )
# filter ALL entities by uuid # Filter ALL entities by uuid, multiple uuids can be specified
parser.add_argument( parser.add_argument(
'--filter-uuid', '--filter-uuid',
action='store', action='append',
dest='filter_uuid', dest='filter_uuid',
default=None, default=[],
help='Filter ALL entities by uuid', help='Filter ALL entities by uuid',
) )
@ -268,14 +304,11 @@ class Command(BaseCommand):
self.stderr.write(f'Exporting entities: {",".join(options["entities"])}') self.stderr.write(f'Exporting entities: {",".join(options["entities"])}')
# Compose filter name for kwargs # Compose filter name for kwargs
filter_kwargs = {} for i in options['filter_name']:
self.filter_args.append(('name__icontains', i))
if options['filter_name']: for i in options['filter_uuid']:
filter_kwargs['name__icontains'] = options['filter_name'] self.filter_args.append(('uuid', i))
if options['filter_uuid']:
filter_kwargs['uuid__icontains'] = options['filter_uuid']
# some entities are redundant, so remove them from the list # some entities are redundant, so remove them from the list
entities = self.remove_reduntant_entities(options['entities']) entities = self.remove_reduntant_entities(options['entities'])
@ -284,23 +317,27 @@ class Command(BaseCommand):
with open(options['output'], 'w') as f: with open(options['output'], 'w') as f:
for entity in entities: for entity in entities:
self.stderr.write(f'Exporting {entity}') self.stderr.write(f'Exporting {entity}')
f.write(self.VALID_ENTITIES[entity](**filter_kwargs)) f.write(self.VALID_ENTITIES[entity]())
f.write('') f.write('')
if self.verbose: if self.verbose:
self.stderr.write(f'Exported to {options["output"]}') self.stderr.write(f'Exported to {options["output"]}')
def apply_filter( def apply_filter(
self, model: typing.Type[ModelType], **kwargs: str self, model: typing.Type[ModelType]
) -> typing.Iterable[ModelType]: ) -> typing.Iterable[ModelType]:
""" """
Applies a filter to a model Applies a filter to a model
""" """
if self.verbose: if self.verbose:
# Explit xxx__icontains=yyy to xxx=yyy # Filter is a filter name, and an array of values
values = [f'{k.split("__")[0]}={v}' for k, v in kwargs.items()] values = [f'{k.split("__")[0]}={v}' for k, v in self.filter_args]
self.stderr.write(f'Filtering {model.__name__} by {",".join(values)}') self.stderr.write(f'Filtering {model.__name__}: \n ', ending='')
yield from model.objects.all().filter(**kwargs) self.stderr.write("\n ".join(values))
# Generate "OR" filter with all kwargs
if self.filter_args:
return model.objects.filter(reduce(operator.or_, (Q(**{k: v}) for k, v in self.filter_args)))
return model.objects.all()
def output_count( def output_count(
self, message: str, iterable: typing.Iterable[T] self, message: str, iterable: typing.Iterable[T]
@ -318,19 +355,19 @@ class Command(BaseCommand):
if self.verbose: if self.verbose:
self.stderr.write('\n') # New line after count self.stderr.write('\n') # New line after count
def export_providers(self, **kwargs: str) -> str: def export_providers(self) -> str:
""" """
Exports all providers to a list of dicts Exports all providers to a list of dicts
""" """
return '# Providers\n' + yaml.safe_dump( return '# Providers\n' + yaml.safe_dump(
[provider_exporter(p) for p in self.apply_filter(models.Provider, **kwargs)] [provider_exporter(p) for p in self.apply_filter(models.Provider)]
) )
def export_services(self, **kwargs: str) -> str: def export_services(self) -> str:
# First, locate providers for services with the filter # First, locate providers for services with the filter
services_list = list( services_list = list(
self.output_count( self.output_count(
'Filtering services', self.apply_filter(models.Service, **kwargs) 'Filtering services', self.apply_filter(models.Service)
) )
) )
providers_list = set( providers_list = set(
@ -358,7 +395,7 @@ class Command(BaseCommand):
+ yaml.safe_dump(services) + yaml.safe_dump(services)
) )
def export_authenticators(self, **kwargs: str) -> str: def export_authenticators(self) -> str:
""" """
Exports all authenticators to a list of dicts Exports all authenticators to a list of dicts
""" """
@ -367,19 +404,19 @@ class Command(BaseCommand):
authenticator_exporter(a) authenticator_exporter(a)
for a in self.output_count( for a in self.output_count(
'Saving authenticators', 'Saving authenticators',
self.apply_filter(models.Authenticator, **kwargs), self.apply_filter(models.Authenticator),
) )
] ]
) )
def export_users(self, **kwargs: str) -> str: def export_users(self) -> str:
""" """
Exports all users to a list of dicts Exports all users to a list of dicts
""" """
# first, locate authenticators for users with the filter # first, locate authenticators for users with the filter
users_list = list( users_list = list(
self.output_count( self.output_count(
'Filtering users', self.apply_filter(models.User, **kwargs) 'Filtering users', self.apply_filter(models.User)
) )
) )
authenticators_list = set( authenticators_list = set(
@ -417,14 +454,14 @@ class Command(BaseCommand):
+ yaml.safe_dump(users) + yaml.safe_dump(users)
) )
def export_groups(self, **kwargs: str) -> str: def export_groups(self) -> str:
""" """
Exports all groups to a list of dicts Exports all groups to a list of dicts
""" """
# First export authenticators for groups with the filter # First export authenticators for groups with the filter
groups_list = list( groups_list = list(
self.output_count( self.output_count(
'Filtering groups', self.apply_filter(models.Group, **kwargs) 'Filtering groups', self.apply_filter(models.Group)
) )
) )
authenticators_list = set( authenticators_list = set(
@ -450,7 +487,7 @@ class Command(BaseCommand):
+ yaml.safe_dump(groups) + yaml.safe_dump(groups)
) )
def export_networks(self, **kwargs: str) -> str: def export_networks(self) -> str:
""" """
Exports all networks to a list of dicts Exports all networks to a list of dicts
""" """
@ -458,19 +495,19 @@ class Command(BaseCommand):
[ [
network_exporter(n) network_exporter(n)
for n in self.output_count( for n in self.output_count(
'Saving networks', self.apply_filter(models.Network, **kwargs) 'Saving networks', self.apply_filter(models.Network)
) )
] ]
) )
def export_transports(self, **kwargs: str) -> str: def export_transports(self) -> str:
""" """
Exports all transports to a list of dicts Exports all transports to a list of dicts
""" """
# First, export networks for transports with the filter # First, export networks for transports with the filter
transports_list = list( transports_list = list(
self.output_count( self.output_count(
'Filtering transports', self.apply_filter(models.Transport, **kwargs) 'Filtering transports', self.apply_filter(models.Transport)
) )
) )
networks_list = set() networks_list = set()
@ -494,7 +531,7 @@ class Command(BaseCommand):
+ yaml.safe_dump(transports) + yaml.safe_dump(transports)
) )
def export_osmanagers(self, **kwargs: str) -> str: def export_osmanagers(self) -> str:
""" """
Exports all osmanagers to a list of dicts Exports all osmanagers to a list of dicts
""" """
@ -502,7 +539,7 @@ class Command(BaseCommand):
[ [
osmanager_exporter(o) osmanager_exporter(o)
for o in self.output_count( for o in self.output_count(
'Saving osmanagers', self.apply_filter(models.OSManager, **kwargs) 'Saving osmanagers', self.apply_filter(models.OSManager)
) )
] ]
) )