old_console/devices/services/endpoint/endpoint_services.py
2024-11-02 14:12:45 +03:00

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'}