230 lines
8.1 KiB
Python
230 lines
8.1 KiB
Python
import base64
|
|
import json
|
|
import logging
|
|
|
|
from django.shortcuts import get_object_or_404
|
|
from rest_framework.exceptions import APIException
|
|
|
|
from devices.models.endpoint_device import EndpointModel
|
|
from devices.serializers.endpoint_serializers import EndpointConfigSerializer
|
|
from devices.services.endpoint.endpoint_get_status import EndpointStatusService
|
|
from devices.services.endpoint.endpoint_redis import RedisInterface
|
|
from devices.services.vector import VectorService
|
|
|
|
_log = logging.getLogger(__name__)
|
|
|
|
|
|
class EndpointException(APIException):
|
|
status_code = 400
|
|
default_detail = 'Cannot create endpoint.'
|
|
|
|
|
|
class EndpointManagementService:
|
|
"""Service to management endpoint."""
|
|
|
|
def __init__(self, instance: EndpointModel) -> None:
|
|
self.instance = instance
|
|
self._log_service = VectorService(instance)
|
|
|
|
def create(self):
|
|
_log.debug(f'Create endpoint logger config')
|
|
try:
|
|
self._log_service.update_config()
|
|
except Exception as err:
|
|
_log.error(f'Cannot create log file: {err}')
|
|
raise EndpointException(str(err))
|
|
|
|
def update(self):
|
|
_log.debug(f'Update endpoint logger config')
|
|
try:
|
|
self._log_service.update_config()
|
|
except Exception as err:
|
|
_log.error(f'Cannot update logger config')
|
|
raise EndpointException(str(err))
|
|
|
|
def destroy(self):
|
|
_log.debug(f'Destroy endpoint logger config')
|
|
try:
|
|
self._log_service.delete_config()
|
|
except Exception as err:
|
|
_log.error(f'Cannot delete logger config')
|
|
raise EndpointException(str(err))
|
|
|
|
|
|
class EndpointKepAliveService:
|
|
|
|
def __init__(self, pk: int, data) -> None:
|
|
self.endpoint = EndpointModel.objects.get(pk=pk)
|
|
self.data = json.loads(data.decode('utf-8'))
|
|
|
|
def get_response(self) -> dict:
|
|
redis_interface = RedisInterface()
|
|
redis_interface.set_keepalive(self.endpoint.pk)
|
|
|
|
status = self.data['status']
|
|
|
|
if status == 'error':
|
|
self.endpoint.config_errors = self.data['errors']
|
|
self.endpoint.incorrect_settings = True
|
|
self.endpoint.save()
|
|
|
|
if self.endpoint.settings_changed and self.data['status'] == 'ok':
|
|
self.endpoint.settings_changed = False
|
|
self.endpoint.incorrect_settings = False
|
|
self.endpoint.config_errors = None
|
|
self.endpoint.save()
|
|
return {'status': 'ok', 'command': 'setting change'}
|
|
|
|
if self.endpoint.request_config:
|
|
return {'status': 'ok', 'command': 'upload'}
|
|
|
|
return {'status': 'ok'}
|
|
|
|
|
|
class EndpointDownloadConfigService:
|
|
def __init__(self, pk: int) -> None:
|
|
self.endpoint = get_object_or_404(EndpointModel, pk=pk)
|
|
|
|
def _dict_to_json(self, config: dict) -> bytes:
|
|
json_str = json.dumps(config, ensure_ascii=False,
|
|
indent=4, sort_keys=True).encode("utf-8")
|
|
return json_str
|
|
|
|
def setup_endpoint(self) -> None:
|
|
if self.endpoint.antivirus_start_scan:
|
|
self.endpoint.antivirus_start_scan = False
|
|
self.endpoint.save()
|
|
|
|
def download(self) -> dict:
|
|
config = self.save_endpoint_settings_to_dict()
|
|
# Serialize data to string
|
|
json_str = self._dict_to_json(config)
|
|
base64_bytes = base64.b64encode(json_str)
|
|
base64_message = base64_bytes.decode("utf-8")
|
|
|
|
response = {
|
|
'status': 'ok',
|
|
'config': base64_message
|
|
}
|
|
return response
|
|
|
|
def save_endpoint_settings_to_dict(self) -> dict:
|
|
"""Convert endpoint model to dict"""
|
|
integrity_control_scan_paths = self.endpoint.scan_paths if self.endpoint.scan_paths else []
|
|
white_list_paths = self.endpoint.white_list_paths if self.endpoint.white_list_paths else []
|
|
antivirus_paths = self.endpoint.antivirus_paths if self.endpoint.antivirus_paths else []
|
|
|
|
config = {
|
|
"device_control": {
|
|
"cd": {
|
|
"deny_read": self.endpoint.prohibit_cd_access,
|
|
"deny_write": self.endpoint.prohibit_cd_access
|
|
},
|
|
"enabled": self.endpoint.device_control_enabled,
|
|
},
|
|
"integrity_control": {
|
|
"control_path": integrity_control_scan_paths,
|
|
"enabled": self.endpoint.integrity_control_enabled,
|
|
"timeout": f'{self.endpoint.integrity_control_timeout}s',
|
|
|
|
},
|
|
"white_list": {
|
|
"enabled": self.endpoint.whitelist_enabled,
|
|
"local_admin": self.endpoint.whitelist_admin,
|
|
"path": white_list_paths,
|
|
},
|
|
"usb_control": {
|
|
"enabled": self.endpoint.usb_control_enabled,
|
|
},
|
|
"antivirus": {
|
|
"start_scan": self.endpoint.antivirus_start_scan,
|
|
"scan_path": antivirus_paths,
|
|
"enabled": self.endpoint.antivirus_enabled,
|
|
"remove_infected_files": self.endpoint.antivirus_remove_infected_files,
|
|
},
|
|
}
|
|
|
|
rotation = {
|
|
'type': self.endpoint.event_rotation_type, # Int
|
|
'size': self.endpoint.event_rotation_size, # Int
|
|
'period': self.endpoint.event_rotation_period, # Int
|
|
'time': self.endpoint.event_rotation_time, # String in format: 01:00:00
|
|
}
|
|
|
|
config['rotation'] = rotation
|
|
return config
|
|
|
|
def download_as_file(self) -> tuple:
|
|
config = self.save_endpoint_settings_to_dict()
|
|
filename = f'endpoint_config_{self.endpoint.pk}.json'
|
|
return self._dict_to_json(config), filename
|
|
|
|
|
|
class EndpointUploadConfigService:
|
|
def __init__(self, pk: int, data) -> None:
|
|
self.endpoint = EndpointModel.objects.get(pk=pk)
|
|
self.data = json.loads(data.decode('utf-8'))
|
|
self.prepare_data()
|
|
|
|
def prepare_data(self):
|
|
"""Data preparation, mapping endpoint fields to DB names."""
|
|
mapping_fields = {
|
|
# Endpoint/MC
|
|
'dc_enabled': 'device_control_enabled',
|
|
|
|
'ic_enabled': 'integrity_control_enabled',
|
|
'scan_folders': 'scan_paths',
|
|
'ic_timeout': 'integrity_control_timeout',
|
|
|
|
'wl_enable': 'whitelist_enabled',
|
|
'wl_admin': 'whitelist_admin',
|
|
'white_list': 'white_list_paths',
|
|
|
|
'clamav_enabled': 'antivirus_enabled',
|
|
'clamav_paths': 'antivirus_paths',
|
|
'clamav_remove_infected_files': 'antivirus_remove_infected_files',
|
|
'clamav_start_scan': 'antivirus_start_scan',
|
|
}
|
|
|
|
self.data['ip'] = self.endpoint.ip
|
|
for alias, field in mapping_fields.items():
|
|
try:
|
|
self.data[field] = self.data[alias]
|
|
except KeyError:
|
|
continue
|
|
|
|
def upload(self):
|
|
serializer = EndpointConfigSerializer(self.endpoint, data=self.data)
|
|
self.endpoint.request_config = False
|
|
if not serializer.is_valid():
|
|
_log.error(serializer.errors)
|
|
self.endpoint.is_requested_config_correct = False
|
|
self.endpoint.save()
|
|
return {'status': 'error', 'error_message': serializer.errors}
|
|
|
|
serializer.update(instance=self.endpoint, validated_data=serializer.validated_data)
|
|
self.endpoint.is_requested_config_correct = True
|
|
self.endpoint.incorrect_settings = False
|
|
self.endpoint.config_errors = None
|
|
self.endpoint.save()
|
|
_log.info(f'Endpoint [{self.endpoint.pk}] updated form endpoint instance')
|
|
return {'status': 'ok'}
|
|
|
|
|
|
class EndpointUpdateService:
|
|
"""Service for update config from endpoint."""
|
|
|
|
def __init__(self, pk: int) -> None:
|
|
self.endpoint = get_object_or_404(EndpointModel, pk=pk)
|
|
self.status_service = EndpointStatusService(self.endpoint)
|
|
|
|
def _update(self) -> None:
|
|
self.endpoint.request_config = True
|
|
self.endpoint.save()
|
|
|
|
def update(self) -> dict:
|
|
status = self.status_service.get_status()['status']
|
|
if status == 'offline':
|
|
raise EndpointException('Endpoint is offline')
|
|
self._update()
|
|
return {'status': 'ok'}
|