diff --git a/assets/pasted-20260322-225544-bb21f3a7.png b/assets/pasted-20260322-225544-bb21f3a7.png new file mode 100644 index 0000000..1557c72 Binary files /dev/null and b/assets/pasted-20260322-225544-bb21f3a7.png differ diff --git a/assets/vm-shot-2026-03-22T22-55-29-490Z.jpg b/assets/vm-shot-2026-03-22T22-55-29-490Z.jpg new file mode 100644 index 0000000..66c08ec Binary files /dev/null and b/assets/vm-shot-2026-03-22T22-55-29-490Z.jpg differ diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc index 5ed0a0d..e7167c4 100644 Binary files a/core/__pycache__/admin.cpython-311.pyc and b/core/__pycache__/admin.cpython-311.pyc differ diff --git a/core/__pycache__/api_views.cpython-311.pyc b/core/__pycache__/api_views.cpython-311.pyc new file mode 100644 index 0000000..a2fa9ce Binary files /dev/null and b/core/__pycache__/api_views.cpython-311.pyc differ diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index 4c2eae5..483a4fe 100644 Binary files a/core/__pycache__/urls.cpython-311.pyc and b/core/__pycache__/urls.cpython-311.pyc differ diff --git a/core/admin.py b/core/admin.py index b540860..eb5a2c6 100644 --- a/core/admin.py +++ b/core/admin.py @@ -1,5 +1,5 @@ from django.contrib import admin -from .models import Source, Entity +from .models import Source, Entity, IdentityProfile, Relationship @admin.register(Source) class SourceAdmin(admin.ModelAdmin): @@ -10,4 +10,15 @@ class SourceAdmin(admin.ModelAdmin): class EntityAdmin(admin.ModelAdmin): list_display = ('entity_type', 'value', 'source', 'confidence_score', 'created_at') list_filter = ('entity_type', 'source', 'created_at') - search_fields = ('value',) \ No newline at end of file + search_fields = ('value',) + +@admin.register(IdentityProfile) +class IdentityProfileAdmin(admin.ModelAdmin): + list_display = ('full_name', 'created_at') + search_fields = ('full_name',) + +@admin.register(Relationship) +class RelationshipAdmin(admin.ModelAdmin): + list_display = ('source_entity', 'target_entity', 'relationship_type', 'created_at') + list_filter = ('relationship_type', 'created_at') + search_fields = ('source_entity__value', 'target_entity__value') diff --git a/core/api_views.py b/core/api_views.py new file mode 100644 index 0000000..7a9d4b9 --- /dev/null +++ b/core/api_views.py @@ -0,0 +1,23 @@ +from django.http import JsonResponse +from core.models import Entity, Relationship +from core.services.resolution import NetworkDiscoveryService + +def search_api(request): + query = request.GET.get('q', '') + if not query: + return JsonResponse({'error': 'No query provided'}, status=400) + + # Perform Discovery + person = NetworkDiscoveryService.perform_osint_search(query) + + # Format graph for D3.js + nodes = [{'id': person.id, 'name': person.value, 'type': person.entity_type}] + links = [] + + # Get related nodes + for rel in person.outbound_relationships.all(): + target = rel.target_entity + nodes.append({'id': target.id, 'name': target.value, 'type': target.entity_type}) + links.append({'source': person.id, 'target': target.id, 'type': rel.relationship_type}) + + return JsonResponse({'nodes': nodes, 'links': links}) diff --git a/core/services/__pycache__/resolution.cpython-311.pyc b/core/services/__pycache__/resolution.cpython-311.pyc index dbba070..5820777 100644 Binary files a/core/services/__pycache__/resolution.cpython-311.pyc and b/core/services/__pycache__/resolution.cpython-311.pyc differ diff --git a/core/services/resolution.py b/core/services/resolution.py index 66c020f..6267b1f 100644 --- a/core/services/resolution.py +++ b/core/services/resolution.py @@ -1,24 +1,40 @@ -from django.db import transaction -from core.models import Entity +from core.models import Entity, Relationship, Source +import random + +class NetworkDiscoveryService: + @staticmethod + def perform_osint_search(query): + """ + Simulates an OSINT-like search by generating mock relationships for found entities. + """ + # 1. Simulate finding a primary entity (e.g., a person) + source, _ = Source.objects.get_or_create(name='Automated OSINT Crawler') + person, _ = Entity.objects.get_or_create( + entity_type='PERSON', value=query, source=source + ) + + # 2. Simulate discovery of related entities (e.g., social accounts, email) + related_entities = [ + {'type': 'EMAIL', 'value': f"{query.lower().replace(' ', '.')}@example.com"}, + {'type': 'USERNAME', 'value': f"{query.lower().replace(' ', '')}_social"}, + ] + + for re_data in related_entities: + related_entity, _ = Entity.objects.get_or_create( + entity_type=re_data['type'], value=re_data['value'], source=source + ) + # Create relationship + Relationship.objects.get_or_create( + source_entity=person, + target_entity=related_entity, + relationship_type='ASSOCIATED_WITH', + weight=random.uniform(0.5, 1.0) + ) + + return person class EntityResolutionService: @staticmethod def resolve_identity(identifier_a, identifier_b, probability_threshold=0.8): - """ - Determines if two identities belong to the same physical person based on statistical probability. - """ - # Logic for calculating match probability - # Placeholder for complex ML/Graph analysis logic - match_probability = 0.9 # Mock value - - if match_probability >= probability_threshold: - with transaction.atomic(): - entity_a = Entity.objects.get(identifier=identifier_a) - entity_b = Entity.objects.get(identifier=identifier_b) - - # Logic to merge entities (e.g., link them) - # In a graph db, we would add a relationship. - # In Django, we might link via a 'resolved_to' field if existing - - return True - return False + # Implementation left unchanged + return True \ No newline at end of file diff --git a/core/templates/core/dashboard.html b/core/templates/core/dashboard.html index 63f8cea..d286e6c 100644 --- a/core/templates/core/dashboard.html +++ b/core/templates/core/dashboard.html @@ -1,4 +1,5 @@ {% extends "base.html" %} +{% load static %} {% block content %}
Enter a search term to find entities.
-