This commit is contained in:
Iliyan Angelov
2025-11-26 22:32:20 +02:00
commit ed94dd22dd
150 changed files with 14058 additions and 0 deletions

View File

View File

View File

@@ -0,0 +1,110 @@
"""
Management command to check security settings and vulnerabilities.
"""
from django.core.management.base import BaseCommand
from django.conf import settings
from django.contrib.auth import get_user_model
from accounts.models import FailedLoginAttempt, ActivityLog
from django.utils import timezone
from datetime import timedelta
User = get_user_model()
class Command(BaseCommand):
help = 'Check security settings and report potential vulnerabilities'
def handle(self, *args, **options):
self.stdout.write(self.style.SUCCESS('=' * 60))
self.stdout.write(self.style.SUCCESS('Security Audit Report'))
self.stdout.write(self.style.SUCCESS('=' * 60))
issues = []
warnings = []
# Check DEBUG mode
if settings.DEBUG:
warnings.append('DEBUG mode is enabled - disable in production!')
else:
self.stdout.write(self.style.SUCCESS('✓ DEBUG mode is disabled'))
# Check SECRET_KEY
if settings.SECRET_KEY == 'django-insecure-change-this-in-production':
issues.append('CRITICAL: Default SECRET_KEY is being used!')
else:
self.stdout.write(self.style.SUCCESS('✓ SECRET_KEY is set'))
# Check ALLOWED_HOSTS
if not settings.ALLOWED_HOSTS:
issues.append('ALLOWED_HOSTS is empty - set in production!')
else:
self.stdout.write(self.style.SUCCESS(f'✓ ALLOWED_HOSTS: {settings.ALLOWED_HOSTS}'))
# Check HTTPS settings
if not settings.DEBUG:
if not getattr(settings, 'SECURE_SSL_REDIRECT', False):
issues.append('SECURE_SSL_REDIRECT should be True in production')
else:
self.stdout.write(self.style.SUCCESS('✓ SSL redirect enabled'))
# Check password hashers
if 'argon2' in settings.PASSWORD_HASHERS[0].lower():
self.stdout.write(self.style.SUCCESS('✓ Using Argon2 password hasher'))
else:
warnings.append('Consider using Argon2 password hasher')
# Check session security
if settings.SESSION_COOKIE_HTTPONLY:
self.stdout.write(self.style.SUCCESS('✓ Session cookies are HTTP-only'))
else:
issues.append('SESSION_COOKIE_HTTPONLY should be True')
if settings.SESSION_COOKIE_SECURE or settings.DEBUG:
self.stdout.write(self.style.SUCCESS('✓ Session cookies are secure'))
else:
issues.append('SESSION_COOKIE_SECURE should be True in production')
# Check CSRF protection
if settings.CSRF_COOKIE_HTTPONLY:
self.stdout.write(self.style.SUCCESS('✓ CSRF cookies are HTTP-only'))
else:
issues.append('CSRF_COOKIE_HTTPONLY should be True')
# Check failed login attempts
recent_failures = FailedLoginAttempt.objects.filter(
timestamp__gte=timezone.now() - timedelta(hours=24)
).count()
if recent_failures > 0:
self.stdout.write(self.style.WARNING(f'{recent_failures} failed login attempts in last 24 hours'))
else:
self.stdout.write(self.style.SUCCESS('✓ No recent failed login attempts'))
# Check for users with weak passwords (if possible)
users_without_mfa = User.objects.filter(mfa_enabled=False).count()
total_users = User.objects.count()
if total_users > 0:
mfa_percentage = (users_without_mfa / total_users) * 100
if mfa_percentage > 50:
warnings.append(f'Only {100-mfa_percentage:.1f}% of users have MFA enabled')
else:
self.stdout.write(self.style.SUCCESS(f'{100-mfa_percentage:.1f}% of users have MFA enabled'))
# Report issues
if issues:
self.stdout.write(self.style.ERROR('\n' + '=' * 60))
self.stdout.write(self.style.ERROR('CRITICAL ISSUES:'))
for issue in issues:
self.stdout.write(self.style.ERROR(f'{issue}'))
if warnings:
self.stdout.write(self.style.WARNING('\n' + '=' * 60))
self.stdout.write(self.style.WARNING('WARNINGS:'))
for warning in warnings:
self.stdout.write(self.style.WARNING(f'{warning}'))
if not issues and not warnings:
self.stdout.write(self.style.SUCCESS('\n✓ No security issues found!'))
self.stdout.write(self.style.SUCCESS('\n' + '=' * 60))

View File

@@ -0,0 +1,45 @@
"""
Management command to create initial scam tags.
"""
from django.core.management.base import BaseCommand
from reports.models import ScamTag
class Command(BaseCommand):
help = 'Create initial scam tags'
def handle(self, *args, **options):
tags = [
{'name': 'Phishing', 'description': 'Phishing scams', 'color': '#dc3545'},
{'name': 'Fake Website', 'description': 'Fake or fraudulent websites', 'color': '#fd7e14'},
{'name': 'Romance Scam', 'description': 'Romance and dating scams', 'color': '#e83e8c'},
{'name': 'Investment Scam', 'description': 'Investment and financial scams', 'color': '#ffc107'},
{'name': 'Tech Support', 'description': 'Tech support scams', 'color': '#20c997'},
{'name': 'Identity Theft', 'description': 'Identity theft attempts', 'color': '#6f42c1'},
{'name': 'Fake Product', 'description': 'Fake product sales', 'color': '#17a2b8'},
{'name': 'Advance Fee', 'description': 'Advance fee fraud', 'color': '#343a40'},
]
created_count = 0
for tag_data in tags:
tag, created = ScamTag.objects.get_or_create(
name=tag_data['name'],
defaults={
'description': tag_data['description'],
'color': tag_data['color']
}
)
if created:
created_count += 1
self.stdout.write(
self.style.SUCCESS(f'Created tag: {tag.name}')
)
else:
self.stdout.write(
self.style.WARNING(f'Tag already exists: {tag.name}')
)
self.stdout.write(
self.style.SUCCESS(f'\nCreated {created_count} new tags.')
)

View File

@@ -0,0 +1,377 @@
"""
Management command to create sample data for testing.
"""
from django.core.management.base import BaseCommand
from django.contrib.auth import get_user_model
from accounts.models import UserProfile, ActivityLog
from reports.models import ScamReport, ScamTag, ScamVerification
from osint.models import OSINTTask, OSINTResult
from moderation.models import ModerationQueue, ModerationAction
from analytics.models import ReportStatistic, UserStatistic
from legal.models import ConsentRecord
from django.utils import timezone
from datetime import timedelta
import random
User = get_user_model()
class Command(BaseCommand):
help = 'Create sample data for testing'
def add_arguments(self, parser):
parser.add_argument(
'--clear',
action='store_true',
help='Clear existing data before creating sample data',
)
def handle(self, *args, **options):
if options['clear']:
self.stdout.write(self.style.WARNING('Clearing existing data...'))
ScamReport.objects.all().delete()
User.objects.filter(is_superuser=False).delete()
ScamTag.objects.all().delete()
self.stdout.write(self.style.SUCCESS('Creating sample data...'))
# Create users
users = self.create_users()
# Create tags
tags = self.create_tags()
# Create reports
reports = self.create_reports(users, tags)
# Create OSINT data
self.create_osint_data(reports, users)
# Create moderation data
self.create_moderation_data(reports, users)
# Create analytics data
self.create_analytics_data()
self.stdout.write(self.style.SUCCESS('\nSample data created successfully!'))
self.stdout.write(self.style.SUCCESS(f'Created {len(users)} users'))
self.stdout.write(self.style.SUCCESS(f'Created {len(tags)} tags'))
self.stdout.write(self.style.SUCCESS(f'Created {len(reports)} reports'))
def create_users(self):
"""Create sample users."""
users = []
# Create admin user
admin, created = User.objects.get_or_create(
username='admin',
defaults={
'email': 'admin@fraudplatform.bg',
'role': 'admin',
'is_verified': True,
'is_staff': True,
}
)
if created:
admin.set_password('admin123')
admin.save()
UserProfile.objects.create(
user=admin,
first_name='Admin',
last_name='User',
consent_given=True,
consent_date=timezone.now()
)
self.stdout.write(self.style.SUCCESS(f'Created admin user: {admin.username}'))
users.append(admin)
# Create moderator users
for i in range(2):
mod, created = User.objects.get_or_create(
username=f'moderator{i+1}',
defaults={
'email': f'moderator{i+1}@fraudplatform.bg',
'role': 'moderator',
'is_verified': True,
}
)
if created:
mod.set_password('mod123')
mod.save()
UserProfile.objects.create(
user=mod,
first_name=f'Moderator{i+1}',
last_name='User',
consent_given=True,
consent_date=timezone.now()
)
self.stdout.write(self.style.SUCCESS(f'Created moderator: {mod.username}'))
users.append(mod)
# Create normal users
user_data = [
('john_doe', 'john@example.com', 'John', 'Doe'),
('jane_smith', 'jane@example.com', 'Jane', 'Smith'),
('ivan_petrov', 'ivan@example.com', 'Ivan', 'Petrov'),
('maria_georgieva', 'maria@example.com', 'Maria', 'Georgieva'),
('test_user', 'test@example.com', 'Test', 'User'),
]
for username, email, first_name, last_name in user_data:
user, created = User.objects.get_or_create(
username=username,
defaults={
'email': email,
'role': 'normal',
'is_verified': True,
}
)
if created:
user.set_password('user123')
user.save()
UserProfile.objects.create(
user=user,
first_name=first_name,
last_name=last_name,
consent_given=True,
consent_date=timezone.now()
)
self.stdout.write(self.style.SUCCESS(f'Created user: {user.username}'))
users.append(user)
return users
def create_tags(self):
"""Create sample tags."""
tag_data = [
('Phishing', 'Phishing scams', '#dc3545'),
('Fake Website', 'Fake or fraudulent websites', '#fd7e14'),
('Romance Scam', 'Romance and dating scams', '#e83e8c'),
('Investment Scam', 'Investment and financial scams', '#ffc107'),
('Tech Support', 'Tech support scams', '#20c997'),
('Identity Theft', 'Identity theft attempts', '#6f42c1'),
('Fake Product', 'Fake product sales', '#17a2b8'),
('Advance Fee', 'Advance fee fraud', '#343a40'),
]
tags = []
for name, description, color in tag_data:
tag, created = ScamTag.objects.get_or_create(
name=name,
defaults={
'description': description,
'color': color
}
)
if created:
self.stdout.write(self.style.SUCCESS(f'Created tag: {tag.name}'))
tags.append(tag)
return tags
def create_reports(self, users, tags):
"""Create sample scam reports."""
normal_users = [u for u in users if u.role == 'normal']
if not normal_users:
return []
report_data = [
{
'title': 'Fake Bulgarian Bank Website',
'description': 'I received an email claiming to be from my bank asking me to verify my account. The website looked identical to the real bank website but the URL was slightly different. When I entered my credentials, I realized it was a phishing attempt.',
'scam_type': 'phishing',
'reported_url': 'https://fake-bank-bg.com',
'reported_email': 'support@fake-bank-bg.com',
'status': 'verified',
'verification_score': 95,
},
{
'title': 'Romance Scam on Dating Site',
'description': 'Someone contacted me on a dating site and after weeks of chatting, asked me to send money for an emergency. I later found out this was a common romance scam pattern.',
'scam_type': 'romance_scam',
'reported_email': 'scammer@example.com',
'reported_phone': '+359888123456',
'status': 'verified',
'verification_score': 88,
},
{
'title': 'Fake Investment Opportunity',
'description': 'Received a call about a "guaranteed" investment opportunity with high returns. They asked for an upfront fee and promised unrealistic returns. This is clearly a scam.',
'scam_type': 'investment_scam',
'reported_phone': '+359888654321',
'reported_company': 'Fake Investment Group',
'status': 'verified',
'verification_score': 92,
},
{
'title': 'Tech Support Scam Call',
'description': 'Received a call from someone claiming to be from Microsoft tech support. They said my computer was infected and asked me to install remote access software. This is a known tech support scam.',
'scam_type': 'tech_support_scam',
'reported_phone': '+359888999888',
'status': 'verified',
'verification_score': 90,
},
{
'title': 'Fake Online Store',
'description': 'Ordered a product from an online store that looked legitimate. After payment, I never received the product and the website disappeared. The products were fake listings.',
'scam_type': 'fake_product',
'reported_url': 'https://fake-store-bg.com',
'reported_email': 'orders@fake-store-bg.com',
'status': 'verified',
'verification_score': 85,
},
{
'title': 'Phishing Email - Tax Refund',
'description': 'Received an email claiming I was eligible for a tax refund. The email asked me to click a link and provide personal information. This is a phishing attempt.',
'scam_type': 'phishing',
'reported_email': 'tax-refund@scam.com',
'status': 'pending',
'verification_score': 0,
},
{
'title': 'Advance Fee Fraud - Lottery Win',
'description': 'Received an email claiming I won a lottery I never entered. They asked for payment of "processing fees" to claim the prize. This is advance fee fraud.',
'scam_type': 'advance_fee',
'reported_email': 'lottery@scam.com',
'status': 'under_review',
'verification_score': 75,
},
{
'title': 'Fake Job Offer',
'description': 'Received a job offer via email that seemed too good to be true. They asked for personal documents and bank account information before any interview. This is a scam.',
'scam_type': 'other',
'reported_email': 'hr@fake-company.com',
'reported_url': 'https://fake-jobs-bg.com',
'status': 'verified',
'verification_score': 87,
},
]
reports = []
for i, data in enumerate(report_data):
reporter = random.choice(normal_users)
created_at = timezone.now() - timedelta(days=random.randint(1, 30))
report = ScamReport.objects.create(
reporter=reporter,
title=data['title'],
description=data['description'],
scam_type=data['scam_type'],
reported_url=data.get('reported_url', ''),
reported_email=data.get('reported_email', ''),
reported_phone=data.get('reported_phone', ''),
reported_company=data.get('reported_company', ''),
status=data['status'],
verification_score=data['verification_score'],
is_public=True if data['status'] == 'verified' else False,
is_anonymous=random.choice([True, False]),
created_at=created_at,
)
# Add random tags
report.tags.set(random.sample(tags, random.randint(1, 3)))
if data['status'] == 'verified':
report.verified_at = created_at + timedelta(hours=random.randint(1, 48))
report.save()
reports.append(report)
self.stdout.write(self.style.SUCCESS(f'Created report: {report.title}'))
return reports
def create_osint_data(self, reports, users):
"""Create sample OSINT data."""
moderators = [u for u in users if u.role in ['moderator', 'admin']]
if not moderators or not reports:
return
for report in reports[:5]: # Add OSINT data to first 5 reports
# Create OSINT tasks
task_types = ['whois_lookup', 'dns_lookup', 'ssl_check', 'email_analysis']
for task_type in random.sample(task_types, 2):
OSINTTask.objects.create(
report=report,
task_type=task_type,
status='completed',
parameters={'target': report.reported_url or report.reported_email or report.reported_phone},
result={'status': 'success', 'data': 'Sample OSINT data'},
started_at=report.created_at + timedelta(minutes=5),
completed_at=report.created_at + timedelta(minutes=10),
)
# Create OSINT results
OSINTResult.objects.create(
report=report,
source='WHOIS Lookup',
data_type='whois',
raw_data={'domain': report.reported_url, 'registrar': 'Fake Registrar'},
processed_data={'risk_level': 'high', 'domain_age': '30 days'},
confidence_level=85,
is_verified=True,
)
self.stdout.write(self.style.SUCCESS(f'Created OSINT data for: {report.title}'))
def create_moderation_data(self, reports, users):
"""Create sample moderation data."""
moderators = [u for u in users if u.role in ['moderator', 'admin']]
if not moderators or not reports:
return
# Add pending reports to moderation queue
pending_reports = [r for r in reports if r.status == 'pending']
for report in pending_reports:
ModerationQueue.objects.create(
report=report,
priority=random.choice(['low', 'normal', 'high']),
assigned_to=random.choice(moderators) if random.choice([True, False]) else None,
)
# Create moderation actions for verified reports
verified_reports = [r for r in reports if r.status == 'verified']
for report in verified_reports:
moderator = random.choice(moderators)
ModerationAction.objects.create(
report=report,
moderator=moderator,
action_type='approve',
previous_status='pending',
new_status='verified',
reason='Verified through OSINT and manual review',
created_at=report.verified_at or report.created_at + timedelta(hours=1),
)
self.stdout.write(self.style.SUCCESS(f'Created moderation data for {len(reports)} reports'))
def create_analytics_data(self):
"""Create sample analytics data."""
today = timezone.now().date()
# Create report statistics for last 7 days
for i in range(7):
date = today - timedelta(days=i)
ReportStatistic.objects.get_or_create(
date=date,
defaults={
'total_reports': ScamReport.objects.filter(created_at__date=date).count(),
'pending_reports': ScamReport.objects.filter(status='pending', created_at__date=date).count(),
'verified_reports': ScamReport.objects.filter(status='verified', created_at__date=date).count(),
'rejected_reports': ScamReport.objects.filter(status='rejected', created_at__date=date).count(),
}
)
# Create user statistics
UserStatistic.objects.get_or_create(
date=today,
defaults={
'total_users': User.objects.count(),
'new_users': User.objects.filter(created_at__date=today).count(),
'active_users': User.objects.filter(last_login__date=today).count(),
'moderators': User.objects.filter(role__in=['moderator', 'admin']).count(),
'admins': User.objects.filter(role='admin').count(),
}
)
self.stdout.write(self.style.SUCCESS('Created analytics data'))

View File

@@ -0,0 +1,120 @@
"""
Management command to create test users for dashboard testing.
"""
from django.core.management.base import BaseCommand
from django.contrib.auth import get_user_model
from accounts.models import UserProfile
from django.utils import timezone
User = get_user_model()
class Command(BaseCommand):
help = 'Create test users (normal, moderator, admin) for dashboard testing'
def handle(self, *args, **options):
self.stdout.write(self.style.SUCCESS('Creating test users...'))
# Create/Update Normal User
normal_user, created = User.objects.get_or_create(
username='normal_user',
defaults={
'email': 'normal@test.bg',
'role': 'normal',
'is_verified': True,
}
)
normal_user.set_password('normal123')
normal_user.role = 'normal'
normal_user.is_verified = True
normal_user.save()
if not hasattr(normal_user, 'profile'):
UserProfile.objects.create(
user=normal_user,
first_name='Normal',
last_name='User',
consent_given=True,
consent_date=timezone.now()
)
self.stdout.write(self.style.SUCCESS(
f'{"Created" if created else "Updated"} normal user: {normal_user.username} (password: normal123)'
))
# Create/Update Moderator User
moderator_user, created = User.objects.get_or_create(
username='moderator',
defaults={
'email': 'moderator@test.bg',
'role': 'moderator',
'is_verified': True,
}
)
moderator_user.set_password('moderator123')
moderator_user.role = 'moderator'
moderator_user.is_verified = True
moderator_user.save()
if not hasattr(moderator_user, 'profile'):
UserProfile.objects.create(
user=moderator_user,
first_name='Moderator',
last_name='User',
consent_given=True,
consent_date=timezone.now()
)
self.stdout.write(self.style.SUCCESS(
f'{"Created" if created else "Updated"} moderator user: {moderator_user.username} (password: moderator123)'
))
# Create/Update Admin User
admin_user, created = User.objects.get_or_create(
username='admin',
defaults={
'email': 'admin@test.bg',
'role': 'admin',
'is_verified': True,
'is_staff': True,
'is_superuser': True,
}
)
admin_user.set_password('admin123')
admin_user.role = 'admin'
admin_user.is_verified = True
admin_user.is_staff = True
admin_user.is_superuser = True
admin_user.save()
if not hasattr(admin_user, 'profile'):
UserProfile.objects.create(
user=admin_user,
first_name='Admin',
last_name='User',
consent_given=True,
consent_date=timezone.now()
)
self.stdout.write(self.style.SUCCESS(
f'{"Created" if created else "Updated"} admin user: {admin_user.username} (password: admin123)'
))
self.stdout.write(self.style.SUCCESS('\n' + '='*60))
self.stdout.write(self.style.SUCCESS('Test Users Created Successfully!'))
self.stdout.write(self.style.SUCCESS('='*60))
self.stdout.write(self.style.SUCCESS('\nLogin Credentials:'))
self.stdout.write(self.style.SUCCESS('\n1. Normal User:'))
self.stdout.write(self.style.SUCCESS(' Username: normal_user'))
self.stdout.write(self.style.SUCCESS(' Password: normal123'))
self.stdout.write(self.style.SUCCESS(' Dashboard: /reports/my-reports/'))
self.stdout.write(self.style.SUCCESS('\n2. Moderator:'))
self.stdout.write(self.style.SUCCESS(' Username: moderator'))
self.stdout.write(self.style.SUCCESS(' Password: moderator123'))
self.stdout.write(self.style.SUCCESS(' Dashboard: /moderation/dashboard/'))
self.stdout.write(self.style.SUCCESS('\n3. Administrator:'))
self.stdout.write(self.style.SUCCESS(' Username: admin'))
self.stdout.write(self.style.SUCCESS(' Password: admin123'))
self.stdout.write(self.style.SUCCESS(' Dashboard: /analytics/dashboard/'))
self.stdout.write(self.style.SUCCESS('\n' + '='*60))