v4.5 Demo initial commit

This commit is contained in:
DaStra3003
2026-06-24 14:53:14 +02:00
commit 3de8ded7c2
110 changed files with 14363112 additions and 0 deletions
+717
View File
@@ -0,0 +1,717 @@
from django.http import JsonResponse
import logging
from django.core.exceptions import ObjectDoesNotExist
from .analyze import analyze_hashes, analyze_url
from .models import *
from .exception_handling import handle_exceptions
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
# Logger configuration
logger = logging.getLogger(__name__)
# Generic function for retrieving objects with error handling and JSON response.
@handle_exceptions
def generic_get_objects(model_class, filter_kwargs=None, select_related_fields=None, message="Objekte"):
# Build queryset
queryset = model_class.objects.all()
if select_related_fields:
queryset = queryset.select_related(*select_related_fields)
if filter_kwargs:
queryset = queryset.filter(**filter_kwargs)
if not queryset.exists():
raise ObjectDoesNotExist(f'Keine {message} gefunden')
data_list = [obj.to_json() for obj in queryset]
return data_list
#Corrected because we need a dictionary as input for Rest
# return JsonResponse({
# 'status': 'success',
# 'message': f'{len(data_list)} {message} gefunden',
# 'data': data_list
# }, status=200)
# Generic function for retrieving a single object by its ID.
@handle_exceptions
def generic_get_object_by_id(model_class, object_id, select_related_fields=None, message="Objekt"):
# Build queryset
queryset = model_class.objects
if select_related_fields:
queryset = queryset.select_related(*select_related_fields)
# Get call raises ObjectDoesNotExist when not found
obj = queryset.get(id=object_id)
return (obj.to_json())
# return {
# 'status': 'success',
# 'message': f'{message} gefunden',
# 'data': [obj.to_json()]
# }
# @handle_exceptions does not need to be used for functions that only call generic functions,
# since the generic functions already contain error handling.
### Manufacturer Functions ###
# Returns all manufacturers.
def get_all_manufacturers():
return generic_get_objects(Manufacturer, message="Hersteller")
# Returns a single manufacturer by its ID.
def get_manufacturer_by_id(manufacturer_id):
return generic_get_object_by_id(Manufacturer, manufacturer_id, message="Hersteller")
### Device Type Functions ###
# Returns all device types.
def get_all_device_types():
return generic_get_objects(DeviceType, message="Gerätetypen")
# Returns a single device type by its ID.
def get_device_type_by_id(device_type_id):
return generic_get_object_by_id(DeviceType, device_type_id, message="Gerätetyp")
# Returns all device types of a specific manufacturer.
def get_device_types_by_manufacturer(manufacturer_id):
return generic_get_objects(
DeviceType,
filter_kwargs={'manufacturer': manufacturer_id},
select_related_fields=['manufacturer'],
message="Gerätetypen"
)
### Product Functions ###
# Returns all products.
def get_all_products():
return generic_get_objects(
Product,
select_related_fields=['manufacturer', 'device_type'],
message="Produkte"
)
# Returns a single product by its ID.
def get_product_by_id(product_id):
return generic_get_object_by_id(
Product,
product_id,
select_related_fields=['manufacturer', 'device_type'],
message="Produkt"
)
# Returns all products of a specific manufacturer.
def get_products_by_manufacturer(manufacturer_id):
return generic_get_objects(
Product,
filter_kwargs={'manufacturer': manufacturer_id},
select_related_fields=['manufacturer', 'device_type'],
message="Produkte"
)
# Returns all products of a specific device type.
def get_products_by_device_type(device_type_id):
return generic_get_objects(
Product,
filter_kwargs={'device_type': device_type_id},
select_related_fields=['manufacturer', 'device_type'],
message="Produkte"
)
### Firmware Functions ###
# Returns all firmwares.
def get_all_firmwares():
return generic_get_objects(
Firmware,
select_related_fields=['product'],
message="Firmwares"
)
# Returns a single firmware by its ID.
def get_firmware_by_id(firmware_id):
return generic_get_object_by_id(
Firmware,
firmware_id,
select_related_fields=['product'],
message="Firmware"
)
# Returns all firmwares of a specific product.
def get_firmwares_by_product(product_id):
return generic_get_objects(
Firmware,
filter_kwargs={'product': product_id},
select_related_fields=['product'],
message="Firmwares"
)
# Returns all firmwares of a specific device.
def get_firmwares_by_device(device_id):
return generic_get_objects(
Firmware,
filter_kwargs={'devices': device_id},
select_related_fields=['product'],
message="Firmwares"
)
### Device Functions ###
##Returns all test devices including the complete manufacturer dataset.
def get_all_devices():
devices = Device.objects.select_related('product', 'product__manufacturer', 'product__device_type')
device_data = []
for device in devices:
device_data.append({
'id': device.id,
'manufacturer_name': device.product.manufacturer.name,
'device_type': device.product.device_type.device_type,
'device_name': device.product.product_name,
'serial': device.serial,
'comment:': device.comment,
'created:': device.created,
})
return device_data
# Returns a single test device by its ID.
def get_devices_by_product(product_id):
return generic_get_objects(
Device,
filter_kwargs={'product': product_id},
select_related_fields=['product'],
message="Geräte"
)
# Returns a single test device by its ID.
def get_device_by_id(device_id):
return generic_get_object_by_id(
Device,
device_id,
select_related_fields=['product'],
message="Gerät"
)
### File Functions ###
# Returns all file entries.
def get_all_files():
return generic_get_objects(
File,
select_related_fields=['firmware', 'device'],
message="Dateien"
)
# Returns a single file entry by its ID.
def get_file_by_id(file_id):
return generic_get_object_by_id(
File,
file_id,
select_related_fields=['firmware', 'device'],
message="Datei"
)
# Returns all file entries of a specific device.
def get_files_by_device(device_id: int):
files = File.objects.filter(device_id=device_id).select_related('firmware', 'firmware__product')
device_data = []
for file in files:
device_data.append({
'id': file.id,
'filename': file.filename,
'ip': file.ip_address,
'state': file.status,
'upload': file.upload_time,
'firmware_version': file.firmware.version,
'product': file.firmware.product.product_name
})
return device_data
# Returns all file entries of a specific firmware.
def get_files_by_firmware(firmware_id):
return generic_get_objects(
File,
filter_kwargs={'firmware': firmware_id},
select_related_fields=['firmware', 'device'],
message="Dateien"
)
### Raw_Data Functions ###
# Returns all raw data from all files.
@handle_exceptions
def get_all_raw_data():
raw_datasets = RawDataset.objects.prefetch_related(
'file',
'dnsraw_set',
'hashraw_set',
'urlraw_set'
).all()
if not raw_datasets.exists():
raise ObjectDoesNotExist('Keine Rohdaten gefunden')
# Extended to_json function for complete data
def raw_dataset_to_detailed_json(dataset):
base_json = dataset.to_json()
base_json.update({
'dns_data': [dns.to_json() for dns in dataset.dnsraw_set.all()],
'hash_data': [hash.to_json() for hash in dataset.hashraw_set.all()],
'url_data': [url.to_json() for url in dataset.urlraw_set.all()]
})
return base_json
data_list = [raw_dataset_to_detailed_json(obj) for obj in raw_datasets]
return JsonResponse({
'status': 'success',
'message': f'{len(data_list)} Rohdaten gefunden',
'data': data_list
}, status=200)
# Tools
# Returns all used tools
def get_all_tools():
return generic_get_objects(
Tool,
message="Tools")
# Returns all raw data for the relevant file.
@handle_exceptions
def get_raw_data_by_file(file_id: int):
raw_dataset = RawDataset.objects.select_related(
'file'
).prefetch_related(
'dnsraw_set',
'hashraw_set',
'urlraw_set'
).get(file_id=file_id)
def raw_dataset_to_detailed_json(dataset):
base_json = dataset.to_json()
base_json.update({
'dns_data': [dns.to_json() for dns in dataset.dnsraw_set.all()],
'hash_data': [hash.to_json() for hash in dataset.hashraw_set.all()],
'url_data': [url.to_json() for url in dataset.urlraw_set.all()]
})
return base_json
detailed_data = raw_dataset_to_detailed_json(raw_dataset)
return {
'status': 'success',
'message': f'Rohdaten für File ID {file_id} gefunden',
'data': detailed_data
}
# Returns all found DNS raw data.
def get_all_dns_raw_data_from_file(file_id: int):
return generic_get_objects(
model_class=DnsRaw,
filter_kwargs={'raw_dataset__file_id': file_id},
select_related_fields=['raw_dataset'],
message="DNS Rohdaten"
)
# Returns all found hash raw data.
def get_all_hash_raw_data_from_file(file_id: int):
return generic_get_objects(
model_class=HashRaw,
filter_kwargs={'raw_dataset__file_id': file_id},
select_related_fields=['raw_dataset'],
message="Hash Rohdaten"
)
# Returns all found URL raw data.
def get_all_url_raw_data_from_file(file_id: int):
return generic_get_objects(
model_class=UrlRaw,
filter_kwargs={'raw_dataset__file_id': file_id},
select_related_fields=['raw_dataset'],
message="URL Rohdaten"
)
### Analyzed_Data Functions ###
# Returns all analyzed data from all files.
@handle_exceptions
def get_all_analyzed_data():
analyzed_datasets = AnalyzedDataset.objects.prefetch_related(
'file',
'dnsanalyzed_set',
'hashanalyzed_set',
'hashanalyzed_set__hash_type',
'urlanalyzed_set',
'urlanalyzed_set__ports',
'urlanalyzed_set__tls_versions',
'urlanalyzed_set__cipher_suites'
).all()
if not analyzed_datasets.exists():
raise ObjectDoesNotExist('Keine analysierten Daten gefunden')
def url_to_detailed_json(url):
return url.to_json()
def analyzed_dataset_to_detailed_json(dataset):
base_json = dataset.to_json()
base_json.update({
'dns_data': [dns.to_json() for dns in dataset.dnsanalyzed_set.all()],
'hash_data': [hash.to_json() for hash in dataset.hashanalyzed_set.all()],
'url_data': [url_to_detailed_json(url) for url in dataset.urlanalyzed_set.all()]
})
return base_json
data_list = [analyzed_dataset_to_detailed_json(obj) for obj in analyzed_datasets]
return{
'status': 'success',
'message': f'{len(data_list)} analysierte Daten gefunden',
'data': data_list
}
# Returns all analyzed data for the relevant file.
@handle_exceptions
def get_analyzed_data_by_file(file_id: int):
select_related_fields = ['file']
prefetch_related_fields = [
'hashanalyzed_set',
'urlanalyzed_set',
'urlanalyzed_set__ports',
'urlanalyzed_set__tls_versions',
'urlanalyzed_set__cipher_suites',
]
# Build queryset
queryset = AnalyzedDataset.objects.select_related(*select_related_fields)
for field in prefetch_related_fields:
queryset = queryset.prefetch_related(field)
# Apply filter
queryset = queryset.filter(file_id=file_id)
if not queryset.exists():
raise ObjectDoesNotExist(f'Keine analysierten Daten für File ID {file_id} gefunden')
# Get single object, since we filter by ID
analyzed_dataset = queryset.get()
# Detail functions for the JSON conversion
def url_to_detailed_json(url):
return url.to_json()
def analyzed_dataset_to_detailed_json(dataset):
base_json = dataset.to_json()
base_json.update({
'dns_data': [dns.to_json() for dns in dataset.dnsanalyzed_set.all()],
'hash_data': [hash.to_json() for hash in dataset.hashanalyzed_set.all()],
'url_data': [url_to_detailed_json(url) for url in dataset.urlanalyzed_set.all()],
})
return base_json
detailed_data = analyzed_dataset_to_detailed_json(analyzed_dataset)
return {
'status': 'success',
'message': f'Analysierte Daten für File ID {file_id} gefunden',
'data': detailed_data
}
# Returns all analyzed DNS data.
def get_all_dns_analyzed_data_from_file(file_id: int):
return generic_get_objects(
model_class=DnsAnalyzed,
filter_kwargs={'analyzed_dataset__file_id': file_id},
select_related_fields=['analyzed_dataset'],
message="DNS analysierte Daten"
)
# Returns all analyzed hash data.
def get_all_hash_analyzed_data_from_file(file_id: int):
return generic_get_objects(
model_class=HashAnalyzed,
filter_kwargs={'analyzed_dataset__file_id': file_id},
select_related_fields=['analyzed_dataset'],
message="Hash analysierte Daten"
)
# Returns all analyzed URL data.
@handle_exceptions
def get_all_url_analyzed_data_from_file(file_id: int):
url_analyzed = UrlAnalyzed.objects.select_related(
'analyzed_dataset'
).prefetch_related(
'ports',
'tls_versions',
'cipher_suites'
).filter(analyzed_dataset__file_id=file_id)
if not url_analyzed.exists():
raise ObjectDoesNotExist('Keine Daten zu analysierten URL gefunden')
data_list = [url.to_json() for url in url_analyzed]
return ({
'status': 'success',
'message': f'Analysierte Daten zu {len(data_list)} URL(s) gefunden',
'data': data_list
})
# Returns all analyzed URL data for a specific raw_url.
@handle_exceptions
def get_all_url_analyzed_by_raw_url_id(raw_url_id: int): ## TODO
raw_url = UrlRaw.objects.get(id=raw_url_id)
analyze_url.get_urls_from_db(raw_url_id)
url_analyzed = UrlAnalyzed.objects.select_related(
'analyzed_dataset',
'tool'
).prefetch_related(
'ports',
'tls_versions',
'cipher_suites'
).filter(
analyzed_dataset__file=raw_url.raw_dataset.file,
).filter(
url=raw_url.url
)
if not url_analyzed.exists():
raise ObjectDoesNotExist(f'Keine analysierten Daten gefunden für URL: {raw_url.url}')
return {
'status': 'success',
'message': f'Analysierte Daten zu URL gefunden',
'data': [url.to_json() for url in url_analyzed]
}
# Returns all analyzed hash data for a specific raw_hash.
@handle_exceptions
def get_all_hash_analyzed_by_raw_hash_id(raw_hash_id: int):
raw_hash = HashRaw.objects.get(id=raw_hash_id)
analyze_hashes.crack_hashes_from_db(raw_hash_id)
hash_analyzed = (HashAnalyzed.objects.select_related(
'analyzed_dataset',
'tool'
).prefetch_related(
'hash_type',)
.filter(
analyzed_dataset__file=raw_hash.raw_dataset.file,
).filter(
hash_value=raw_hash.hash_value
))
if not hash_analyzed.exists():
raise ObjectDoesNotExist(f'Keine analysierten Daten gefunden für Hash: {raw_hash.hash_value}')
return {
'status': 'success',
'message': f'Analysierte Daten zu gefunden',
'data': [hash.to_json() for hash in hash_analyzed]
}
### Firmware analysis READ functions ###
# Returns all binwalk raw data of a file
def get_all_binwalk_raw_data_from_file(file_id: int):
"""
Returns all binwalk raw data for a specific file.
"""
return generic_get_objects(
model_class=BinwalkRaw,
filter_kwargs={'raw_dataset__file_id': file_id},
select_related_fields=['raw_dataset'],
message="Binwalk Rohdaten"
)
# Returns all strings raw data of a file
def get_all_strings_raw_data_from_file(file_id: int):
"""
Returns all strings raw data for a specific file.
"""
return generic_get_objects(
model_class=StringsRaw,
filter_kwargs={'raw_dataset__file_id': file_id},
select_related_fields=['raw_dataset'],
message="Strings Rohdaten"
)
# Returns filtered strings by type
def get_strings_by_type(file_id: int, string_type: str):
"""
Returns filtered strings by type (url, ip, path, etc.).
"""
return generic_get_objects(
model_class=StringsRaw,
filter_kwargs={
'raw_dataset__file_id': file_id,
'string_type': string_type
},
select_related_fields=['raw_dataset'],
message=f"Strings vom Typ {string_type}"
)
# Returns all analyzed binwalk data of a file
@handle_exceptions
def get_all_binwalk_analyzed_data_from_file(file_id: int):
"""
Returns all analyzed binwalk data for a specific file.
"""
binwalk_analyzed = BinwalkAnalyzed.objects.select_related(
'analyzed_dataset',
'tool'
).filter(analyzed_dataset__file_id=file_id)
if not binwalk_analyzed.exists():
raise ObjectDoesNotExist('Keine analysierten Binwalk-Daten gefunden')
data_list = [entry.to_json() for entry in binwalk_analyzed]
return {
'status': 'success',
'message': f'Analysierte Binwalk-Daten zu {len(data_list)} Einträgen gefunden',
'data': data_list
}
# Returns all analyzed strings data of a file
@handle_exceptions
def get_all_strings_analyzed_data_from_file(file_id: int):
"""
Returns all analyzed strings data for a specific file.
"""
strings_analyzed = StringsAnalyzed.objects.select_related(
'analyzed_dataset',
'tool'
).filter(analyzed_dataset__file_id=file_id)
if not strings_analyzed.exists():
raise ObjectDoesNotExist('Keine analysierten Strings-Daten gefunden')
data_list = [entry.to_json() for entry in strings_analyzed]
return {
'status': 'success',
'message': f'Analysierte Strings-Daten zu {len(data_list)} Einträgen gefunden',
'data': data_list
}
# Returns critical strings by severity
@handle_exceptions
def get_critical_strings_by_severity(file_id: int, min_severity: str = 'medium'):
"""
Returns critical strings filtered by minimum severity.
"""
severity_order = {'info': 0, 'low': 1, 'medium': 2, 'high': 3, 'critical': 4}
min_level = severity_order.get(min_severity, 0)
strings_analyzed = StringsAnalyzed.objects.select_related(
'analyzed_dataset',
'tool'
).filter(analyzed_dataset__file_id=file_id)
# Filter by severity
filtered_strings = [
entry for entry in strings_analyzed
if severity_order.get(entry.severity, 0) >= min_level
]
if not filtered_strings:
raise ObjectDoesNotExist(f'Keine Strings mit Severity >= {min_severity} gefunden')
data_list = [entry.to_json() for entry in filtered_strings]
return {
'status': 'success',
'message': f'{len(data_list)} kritische Strings gefunden',
'data': data_list
}
# Extended get_raw_data_by_file function (replaces the existing one)
@handle_exceptions
def get_raw_data_by_file_extended(file_id: int):
"""
Returns ALL raw data for a file (incl. firmware data).
"""
raw_dataset = RawDataset.objects.select_related(
'file'
).prefetch_related(
'dnsraw_set',
'hashraw_set',
'urlraw_set',
'binwalkraw_set',
'stringsraw_set'
).get(file_id=file_id)
def raw_dataset_to_detailed_json(dataset):
base_json = dataset.to_json()
base_json.update({
'dns_data': [dns.to_json() for dns in dataset.dnsraw_set.all()],
'hash_data': [hash.to_json() for hash in dataset.hashraw_set.all()],
'url_data': [url.to_json() for url in dataset.urlraw_set.all()],
'binwalk_data': [binwalk.to_json() for binwalk in dataset.binwalkraw_set.all()],
'strings_data': [string.to_json() for string in dataset.stringsraw_set.all()]
})
return base_json
detailed_data = raw_dataset_to_detailed_json(raw_dataset)
return {
'status': 'success',
'message': f'Vollständige Rohdaten für File ID {file_id} gefunden',
'data': detailed_data
}
# Add import statements at the beginning of db_read.py:
# from .models import BinwalkRaw, StringsRaw, BinwalkAnalyzed, StringsAnalyzed