diff --git a/backEnd/gnx/__pycache__/settings.cpython-312.pyc b/backEnd/gnx/__pycache__/settings.cpython-312.pyc index 431ec15e..0ad5b231 100644 Binary files a/backEnd/gnx/__pycache__/settings.cpython-312.pyc and b/backEnd/gnx/__pycache__/settings.cpython-312.pyc differ diff --git a/backEnd/gnx/middleware/__pycache__/api_security.cpython-312.pyc b/backEnd/gnx/middleware/__pycache__/api_security.cpython-312.pyc new file mode 100644 index 00000000..bc482812 Binary files /dev/null and b/backEnd/gnx/middleware/__pycache__/api_security.cpython-312.pyc differ diff --git a/backEnd/gnx/middleware/api_security.py b/backEnd/gnx/middleware/api_security.py new file mode 100644 index 00000000..f4ce87c4 --- /dev/null +++ b/backEnd/gnx/middleware/api_security.py @@ -0,0 +1,145 @@ +""" +API Security Middleware +Validates that API requests come from the frontend through nginx reverse proxy +This ensures the API is only accessible from the frontend, not directly from the internet +""" + +from django.http import HttpResponseForbidden, JsonResponse +from django.conf import settings +from django.utils.deprecation import MiddlewareMixin +import logging +import re + +logger = logging.getLogger('django.security') + + +class FrontendAPIProxyMiddleware(MiddlewareMixin): + """ + Enterprise Security: Only allow API requests from frontend through nginx + + This middleware validates: + 1. Custom header (X-Internal-API-Key) that nginx adds to prove request came through proxy + 2. Origin/Referer header matches allowed frontend domains + 3. Request comes from internal network (nginx proxy) + + In production, this ensures the API cannot be accessed directly from the internet. + All requests must come through the frontend (nginx reverse proxy). + """ + + def __init__(self, get_response): + self.get_response = get_response + super().__init__(get_response) + + # Get API key from settings (nginx will add this header) + self.required_api_key = getattr(settings, 'INTERNAL_API_KEY', None) + + # Get allowed frontend origins + self.allowed_origins = getattr(settings, 'CORS_ALLOWED_ORIGINS', []) + + # Get allowed referer patterns + self.allowed_referer_patterns = getattr(settings, 'ALLOWED_REFERER_PATTERNS', []) + + # API paths that require validation (default: all /api/ paths) + self.api_path_pattern = getattr(settings, 'API_SECURITY_PATH_PATTERN', r'^/api/') + + # Skip validation in DEBUG mode for development + self.enforce_in_debug = getattr(settings, 'ENFORCE_API_SECURITY_IN_DEBUG', False) + + def process_request(self, request): + """ + Validate API requests come from frontend through nginx + """ + # Skip validation for non-API paths + if not re.match(self.api_path_pattern, request.path): + return None + + # Skip validation in DEBUG mode unless explicitly enabled + if settings.DEBUG and not self.enforce_in_debug: + return None + + # Skip validation for OPTIONS requests (CORS preflight) + if request.method == 'OPTIONS': + return None + + # Get the internal API key from header (added by nginx) + internal_api_key = request.META.get('HTTP_X_INTERNAL_API_KEY', '') + + # Validate API key if configured + if self.required_api_key: + if internal_api_key != self.required_api_key: + logger.warning( + f"Blocked API request: Missing or invalid X-Internal-API-Key header. " + f"Path: {request.path}, IP: {self._get_client_ip(request)}" + ) + return JsonResponse( + { + 'error': 'Access Denied', + 'message': 'This API is only accessible through the frontend application.', + 'code': 'API_ACCESS_DENIED' + }, + status=403 + ) + + # Validate Origin header (for CORS requests) + origin = request.META.get('HTTP_ORIGIN', '') + if origin: + if origin not in self.allowed_origins: + logger.warning( + f"Blocked API request: Invalid Origin header. " + f"Origin: {origin}, Path: {request.path}, IP: {self._get_client_ip(request)}" + ) + return JsonResponse( + { + 'error': 'Access Denied', + 'message': 'Invalid origin. This API is only accessible from authorized domains.', + 'code': 'INVALID_ORIGIN' + }, + status=403 + ) + + # Validate Referer header (for same-origin requests) + referer = request.META.get('HTTP_REFERER', '') + if referer and not origin: # Only check referer if no origin header + is_valid_referer = False + + # Check against allowed origins + for allowed_origin in self.allowed_origins: + if referer.startswith(allowed_origin): + is_valid_referer = True + break + + # Check against referer patterns + if not is_valid_referer and self.allowed_referer_patterns: + for pattern in self.allowed_referer_patterns: + if re.match(pattern, referer): + is_valid_referer = True + break + + if not is_valid_referer: + logger.warning( + f"Blocked API request: Invalid Referer header. " + f"Referer: {referer}, Path: {request.path}, IP: {self._get_client_ip(request)}" + ) + return JsonResponse( + { + 'error': 'Access Denied', + 'message': 'Invalid referer. This API is only accessible from authorized domains.', + 'code': 'INVALID_REFERER' + }, + status=403 + ) + + # Additional validation: Check if request comes from nginx (internal network) + # This is a secondary check - the IP whitelist middleware should handle this, + # but we can add additional validation here if needed + + # Request is valid, continue processing + return None + + def _get_client_ip(self, request): + """Get client IP address from request""" + x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') + if x_forwarded_for: + return x_forwarded_for.split(',')[0].strip() + return request.META.get('REMOTE_ADDR', 'unknown') + diff --git a/backEnd/gnx/settings.py b/backEnd/gnx/settings.py index 4ab3907c..2f97caa8 100644 --- a/backEnd/gnx/settings.py +++ b/backEnd/gnx/settings.py @@ -62,6 +62,7 @@ MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', 'django.middleware.security.SecurityMiddleware', 'gnx.middleware.ip_whitelist.IPWhitelistMiddleware', # Production: Block external access + 'gnx.middleware.api_security.FrontendAPIProxyMiddleware', # Validate requests from frontend/nginx 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', @@ -151,7 +152,7 @@ CSRF_COOKIE_HTTPONLY = True CSRF_COOKIE_SAMESITE = 'Strict' CSRF_TRUSTED_ORIGINS = config( 'CSRF_TRUSTED_ORIGINS', - default='https://gnxsoft.com', + default='https://gnxsoft.com,https://www.gnxsoft.com', cast=lambda v: [s.strip() for s in v.split(',')] ) @@ -229,7 +230,31 @@ REST_FRAMEWORK = { }, } -# CORS Configuration +# ============================================================================ +# API SECURITY CONFIGURATION +# API is only accessible from frontend through nginx reverse proxy +# ============================================================================ + +# Internal API Key - nginx will add this header to prove request came through proxy +# Generate a strong random key: python -c "import secrets; print(secrets.token_urlsafe(32))" +INTERNAL_API_KEY = config('INTERNAL_API_KEY', default='' if not DEBUG else 'dev-key-change-in-production') + +# API security path pattern (default: all /api/ paths) +API_SECURITY_PATH_PATTERN = config('API_SECURITY_PATH_PATTERN', default=r'^/api/') + +# Enforce API security even in DEBUG mode (for testing) +ENFORCE_API_SECURITY_IN_DEBUG = config('ENFORCE_API_SECURITY_IN_DEBUG', default=False, cast=bool) + +# Allowed referer patterns (regex patterns for referer validation) +ALLOWED_REFERER_PATTERNS = config( + 'ALLOWED_REFERER_PATTERNS', + default='', + cast=lambda v: [s.strip() for s in v.split(',') if s.strip()] +) + +# ============================================================================ +# CORS Configuration - Strict origin validation +# ============================================================================ CORS_ALLOWED_ORIGINS = [ "http://localhost:3000", # React development server "http://127.0.0.1:3000", @@ -237,14 +262,43 @@ CORS_ALLOWED_ORIGINS = [ "http://127.0.0.1:3001", ] -# Add production origins if configured -PRODUCTION_ORIGINS = config('PRODUCTION_ORIGINS', default='', cast=lambda v: [s.strip() for s in v.split(',') if s.strip()]) +# Add production origins if configured (defaults to gnxsoft.com domains) +PRODUCTION_ORIGINS = config( + 'PRODUCTION_ORIGINS', + default='https://gnxsoft.com,https://www.gnxsoft.com', + cast=lambda v: [s.strip() for s in v.split(',') if s.strip()] +) if PRODUCTION_ORIGINS: CORS_ALLOWED_ORIGINS.extend(PRODUCTION_ORIGINS) +# Strict CORS configuration - only allow configured origins CORS_ALLOW_CREDENTIALS = True +CORS_ALLOW_ALL_ORIGINS = False # Never allow all origins, even in development +CORS_ALLOWED_ORIGIN_REGEXES = [] # No regex patterns by default -CORS_ALLOW_ALL_ORIGINS = DEBUG # Only allow all origins in development +# CORS allowed methods +CORS_ALLOW_METHODS = [ + 'DELETE', + 'GET', + 'OPTIONS', + 'PATCH', + 'POST', + 'PUT', +] + +# CORS allowed headers +CORS_ALLOW_HEADERS = [ + 'accept', + 'accept-encoding', + 'authorization', + 'content-type', + 'dnt', + 'origin', + 'user-agent', + 'x-csrftoken', + 'x-requested-with', + 'x-internal-api-key', # Custom header for nginx validation +] # Django URL configuration APPEND_SLASH = True diff --git a/backEnd/logs/django.log b/backEnd/logs/django.log index 0bb9aa02..88f262e9 100644 --- a/backEnd/logs/django.log +++ b/backEnd/logs/django.log @@ -32835,3 +32835,45 @@ INFO 2025-11-24 06:12:16,803 basehttp 108393 126550263457472 "GET /api/services/ INFO 2025-11-24 06:12:16,840 basehttp 108393 126550263457472 "GET /api/services/?ordering=display_order&page=1 HTTP/1.1" 200 10722 INFO 2025-11-24 06:13:09,003 basehttp 108393 126550263457472 "GET /api/services/?ordering=display_order&page=1 HTTP/1.1" 200 10722 INFO 2025-11-24 06:13:09,043 basehttp 108393 126550263457472 "GET /api/services/?ordering=display_order&page=1 HTTP/1.1" 200 10722 +INFO 2025-11-24 06:36:47,411 basehttp 108393 126550271850176 "GET /api/career/jobs HTTP/1.1" 200 4675 +INFO 2025-11-24 06:36:47,412 basehttp 108393 126550263457472 "GET /api/services/?ordering=display_order&page=1 HTTP/1.1" 200 10722 +INFO 2025-11-24 06:36:47,426 basehttp 108393 126550271850176 "GET /api/career/jobs HTTP/1.1" 200 4675 +INFO 2025-11-24 06:36:47,430 basehttp 108393 126550263457472 "GET /api/services/?ordering=display_order&page=1 HTTP/1.1" 200 10722 +INFO 2025-11-24 06:36:47,488 basehttp 108393 126550263457472 "GET /api/services/?ordering=display_order&page=1 HTTP/1.1" 200 10722 +INFO 2025-11-24 06:36:47,493 basehttp 108393 126550271850176 "GET /api/services/?ordering=display_order&page=1 HTTP/1.1" 200 10722 +INFO 2025-11-24 06:36:57,635 basehttp 108393 126550271850176 "OPTIONS /api/services/?ordering=display_order&page=1 HTTP/1.1" 200 0 +INFO 2025-11-24 06:36:57,637 basehttp 108393 126550271850176 "OPTIONS /api/career/jobs HTTP/1.1" 200 0 +INFO 2025-11-24 06:36:57,658 basehttp 108393 126550263457472 "GET /api/services/?ordering=display_order&page=1 HTTP/1.1" 200 10722 +INFO 2025-11-24 06:36:57,668 basehttp 108393 126550263457472 "GET /api/services/?ordering=display_order&page=1 HTTP/1.1" 200 10722 +INFO 2025-11-24 06:36:57,693 basehttp 108393 126550271850176 "GET /api/career/jobs HTTP/1.1" 200 4675 +INFO 2025-11-24 06:37:09,801 basehttp 108393 126550263457472 "GET /api/services/?ordering=display_order&page=1 HTTP/1.1" 200 10722 +INFO 2025-11-24 06:37:09,806 basehttp 108393 126550632552128 "OPTIONS /api/home/banner/ HTTP/1.1" 200 0 +INFO 2025-11-24 06:37:09,807 basehttp 108393 126550623110848 "OPTIONS /api/case-studies/?ordering=display_order&page_size=5 HTTP/1.1" 200 0 +INFO 2025-11-24 06:37:09,826 basehttp 108393 126550649337536 "OPTIONS /api/blog/posts/latest/?limit=12 HTTP/1.1" 200 0 +INFO 2025-11-24 06:37:09,842 basehttp 108393 126550263457472 "GET /api/services/?ordering=display_order&page=1 HTTP/1.1" 200 10722 +INFO 2025-11-24 06:37:09,843 basehttp 108393 126550271850176 "GET /api/career/jobs HTTP/1.1" 200 4675 +INFO 2025-11-24 06:37:09,847 basehttp 108393 126550640944832 "GET /api/home/banner/ HTTP/1.1" 200 3438 +INFO 2025-11-24 06:37:09,863 basehttp 108393 126550632552128 "GET /api/case-studies/?ordering=display_order&page_size=5 HTTP/1.1" 200 4744 +INFO 2025-11-24 06:37:09,868 basehttp 108393 126550640944832 "GET /api/home/banner/ HTTP/1.1" 200 3438 +INFO 2025-11-24 06:37:09,878 basehttp 108393 126550271850176 "GET /api/career/jobs HTTP/1.1" 200 4675 +INFO 2025-11-24 06:37:09,898 basehttp 108393 126550263457472 "GET /api/services/?ordering=display_order&page=1 HTTP/1.1" 200 10722 +INFO 2025-11-24 06:37:09,909 basehttp 108393 126550623110848 "GET /api/blog/posts/latest/?limit=12 HTTP/1.1" 200 8374 +INFO 2025-11-24 06:37:09,915 basehttp 108393 126550632552128 "GET /api/case-studies/?ordering=display_order&page_size=5 HTTP/1.1" 200 4744 +INFO 2025-11-24 06:37:09,955 basehttp 108393 126550263457472 "GET /api/services/?ordering=display_order&page=1 HTTP/1.1" 200 10722 +INFO 2025-11-24 06:37:09,976 basehttp 108393 126550623110848 "GET /api/blog/posts/latest/?limit=12 HTTP/1.1" 200 8374 +INFO 2025-11-24 06:37:10,010 basehttp 108393 126550263457472 "GET /api/services/?ordering=display_order&page=1 HTTP/1.1" 200 10722 +INFO 2025-11-24 06:37:10,060 basehttp 108393 126550263457472 "GET /api/services/?ordering=display_order&page=1 HTTP/1.1" 200 10722 +INFO 2025-11-24 06:39:11,537 autoreload 108393 126550715764864 /home/gnx/Desktop/GNX-WEB/backEnd/gnx/settings.py changed, reloading. +INFO 2025-11-24 06:39:12,172 autoreload 139522 135175989801088 Watching for file changes with StatReloader +INFO 2025-11-24 06:39:24,941 autoreload 139522 135175989801088 /home/gnx/Desktop/GNX-WEB/backEnd/gnx/settings.py changed, reloading. +INFO 2025-11-24 06:39:25,492 autoreload 139604 123745838387328 Watching for file changes with StatReloader +INFO 2025-11-24 06:39:59,747 autoreload 139604 123745838387328 /home/gnx/Desktop/GNX-WEB/backEnd/gnx/settings.py changed, reloading. +INFO 2025-11-24 06:40:00,322 autoreload 139793 134765910855808 Watching for file changes with StatReloader +INFO 2025-11-24 06:40:19,231 autoreload 139793 134765910855808 /home/gnx/Desktop/GNX-WEB/backEnd/gnx/settings.py changed, reloading. +INFO 2025-11-24 06:40:19,802 autoreload 139883 138604311842944 Watching for file changes with StatReloader +INFO 2025-11-24 06:40:25,359 autoreload 139883 138604311842944 /home/gnx/Desktop/GNX-WEB/backEnd/gnx/settings.py changed, reloading. +INFO 2025-11-24 06:40:25,924 autoreload 139932 123776047718528 Watching for file changes with StatReloader +INFO 2025-11-24 06:40:57,132 autoreload 139932 123776047718528 /home/gnx/Desktop/GNX-WEB/backEnd/gnx/settings.py changed, reloading. +INFO 2025-11-24 06:40:57,712 autoreload 140119 136966227431552 Watching for file changes with StatReloader +INFO 2025-11-24 06:41:38,174 autoreload 140119 136966227431552 /home/gnx/Desktop/GNX-WEB/backEnd/gnx/settings.py changed, reloading. +INFO 2025-11-24 06:41:38,716 autoreload 140239 133780171337856 Watching for file changes with StatReloader diff --git a/backEnd/nginx.conf.example b/backEnd/nginx.conf.example new file mode 100644 index 00000000..29df60de --- /dev/null +++ b/backEnd/nginx.conf.example @@ -0,0 +1,173 @@ +# Nginx Configuration Example for GNX Web Application +# This configuration shows how to set up nginx as a reverse proxy +# to secure the Django API backend + +# Generate a secure API key for INTERNAL_API_KEY: +# python -c "import secrets; print(secrets.token_urlsafe(32))" +# Add this key to your Django .env file as INTERNAL_API_KEY + +upstream django_backend { + # Django backend running on internal network only + server 127.0.0.1:8000; + keepalive 32; +} + +upstream nextjs_frontend { + # Next.js frontend + server 127.0.0.1:3000; + keepalive 32; +} + +# Rate limiting zones +limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s; +limit_req_zone $binary_remote_addr zone=general_limit:10m rate=30r/s; + +server { + listen 80; + server_name gnxsoft.com www.gnxsoft.com; + + # Redirect HTTP to HTTPS + return 301 https://$server_name$request_uri; +} + +server { + listen 443 ssl http2; + server_name gnxsoft.com www.gnxsoft.com; + + # SSL Configuration + ssl_certificate /etc/letsencrypt/live/gnxsoft.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/gnxsoft.com/privkey.pem; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + + # Security Headers + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; + add_header X-Frame-Options "DENY" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';" always; + + # Logging + access_log /var/log/nginx/gnxsoft_access.log; + error_log /var/log/nginx/gnxsoft_error.log; + + # Client body size limit + client_max_body_size 10M; + + # API Endpoints - Proxy to Django backend + # These requests will have the X-Internal-API-Key header added + location /api/ { + # Rate limiting + limit_req zone=api_limit burst=20 nodelay; + + # Add custom header to prove request came through nginx + # This value must match INTERNAL_API_KEY in Django settings + set $api_key "YOUR_SECURE_API_KEY_HERE"; + proxy_set_header X-Internal-API-Key $api_key; + + # Standard proxy headers + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Port $server_port; + + # Preserve original request headers + proxy_set_header Origin $http_origin; + proxy_set_header Referer $http_referer; + + # Proxy settings + proxy_pass http://django_backend; + proxy_redirect off; + proxy_http_version 1.1; + proxy_set_header Connection ""; + + # Timeouts + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + + # Buffering + proxy_buffering on; + proxy_buffer_size 4k; + proxy_buffers 8 4k; + proxy_busy_buffers_size 8k; + } + + # Media files - Serve from Django + location /media/ { + alias /path/to/gnx/backEnd/media/; + expires 30d; + add_header Cache-Control "public, immutable"; + access_log off; + } + + # Static files - Serve from Django + location /static/ { + alias /path/to/gnx/backEnd/staticfiles/; + expires 30d; + add_header Cache-Control "public, immutable"; + access_log off; + } + + # Admin panel - Only allow from specific IPs (optional) + location /admin/ { + # Uncomment to restrict admin access + # allow 192.168.1.0/24; + # allow 10.0.0.0/8; + # deny all; + + # Same proxy settings as /api/ + set $api_key "YOUR_SECURE_API_KEY_HERE"; + proxy_set_header X-Internal-API-Key $api_key; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_pass http://django_backend; + proxy_redirect off; + proxy_http_version 1.1; + proxy_set_header Connection ""; + } + + # Frontend - Proxy to Next.js + location / { + # Rate limiting + limit_req zone=general_limit burst=50 nodelay; + + # Proxy to Next.js frontend + proxy_pass http://nextjs_frontend; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_cache_bypass $http_upgrade; + + # Timeouts + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + # Health check endpoint (optional) + location /health { + access_log off; + return 200 "healthy\n"; + add_header Content-Type text/plain; + } +} + +# Block direct access to backend port 8000 from external IPs +# This should be done at the firewall level: +# ufw deny 8000 +# iptables -A INPUT -p tcp --dport 8000 ! -s 127.0.0.1 -j DROP + diff --git a/backEnd/production.env.example b/backEnd/production.env.example index 74094691..53e2b216 100644 --- a/backEnd/production.env.example +++ b/backEnd/production.env.example @@ -4,7 +4,7 @@ # Django Settings SECRET_KEY=your-super-secret-production-key-here DEBUG=False -ALLOWED_HOSTS=yourdomain.com,www.yourdomain.com,your-server-ip +ALLOWED_HOSTS=gnxsoft.com,www.gnxsoft.com,your-server-ip # Database - Using SQLite (default) # SQLite is configured in settings.py - no DATABASE_URL needed @@ -37,9 +37,16 @@ SECURE_BROWSER_XSS_FILTER=True X_FRAME_OPTIONS=DENY # CORS Settings (Production) -CORS_ALLOWED_ORIGINS=https://yourdomain.com,https://www.yourdomain.com +PRODUCTION_ORIGINS=https://gnxsoft.com,https://www.gnxsoft.com CORS_ALLOW_CREDENTIALS=True +# CSRF Trusted Origins +CSRF_TRUSTED_ORIGINS=https://gnxsoft.com,https://www.gnxsoft.com + +# API Security - Internal API Key (nginx will add this header) +# Generate a secure key: python -c "import secrets; print(secrets.token_urlsafe(32))" +INTERNAL_API_KEY=your-secure-api-key-here-change-this-in-production + # Static Files STATIC_ROOT=/var/www/gnx/staticfiles/ MEDIA_ROOT=/var/www/gnx/media/ diff --git a/frontEnd/app/about-us/AboutUsClient.tsx b/frontEnd/app/about-us/AboutUsClient.tsx new file mode 100644 index 00000000..ca045831 --- /dev/null +++ b/frontEnd/app/about-us/AboutUsClient.tsx @@ -0,0 +1,27 @@ +"use client"; +import Header from "@/components/shared/layout/header/Header"; +import AboutBanner from "@/components/pages/about/AboutBanner"; +import AboutServiceComponent from "@/components/pages/about/AboutService"; +import Footer from "@/components/shared/layout/footer/Footer"; +import AboutScrollProgressButton from "@/components/pages/about/AboutScrollProgressButton"; +import AboutInitAnimations from "@/components/pages/about/AboutInitAnimations"; +import AboutStarter from "@/components/pages/about/AboutStarter"; + +const AboutUsClient = () => { + return ( +