Spaces:
No application file

File size: 7,628 Bytes
839a850
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
import asyncio
import os
import logging
from typing import List, Dict, Any, Optional
from fastapi import FastAPI, Query, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel
from dotenv import load_dotenv

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

load_dotenv()

from connectors.intelligencex import search_intelx
from connectors.enisa_cve import fetch_enisa_cve
#from connectors.maltego import fetch_from_maltego
#from connectors.shodan import search_shodan
from connectors.virustotal import search_virustotal

from core.normalize import normalize_intelx_data, normalize_shodan_data, normalize_virustotal_data
from core.correlate import correlate_entities
from core.risk_engine import assess_risk
from llm_agent.llm_chatGPT import load_llm
from llm_agent.prompt_templates import get_summary_prompt

app = FastAPI(
    title="OSINT Early Warning System",
    description="An intelligence gathering and analysis API",
    version="1.0.0"
)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # Consider restricting this in production
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Mount static files for frontend
frontend_path = os.path.join(os.path.dirname(__file__), "../osint-early-warning/frontend/build")
if os.path.exists(frontend_path):
    app.mount(
        "/",
        StaticFiles(directory=frontend_path, html=True),
        name="frontend",
    )
else:
    logger.warning(f"Frontend directory not found: {frontend_path}")

class SummaryResponse(BaseModel):
    summary: str
    risk_level: str
    confidence: float
    sources_used: List[str]
    timestamp: str

class ErrorResponse(BaseModel):
    error: str
    details: Optional[str] = None

@app.get("/api/health")
async def health_check():
    """Health check endpoint"""
    return {"status": "healthy", "version": "1.0.0"}

@app.get("/api/osint", response_model=SummaryResponse, responses={400: {"model": ErrorResponse}})
async def osint_summary(entity: str = Query(..., min_length=1, max_length=255)):
    """
    Perform OSINT analysis on a given entity
    
    Args:
        entity: The target entity to analyze (IP, domain, hash, etc.)
    
    Returns:
        Comprehensive analysis summary with risk assessment
    """
    try:
        logger.info(f"Starting OSINT analysis for entity: {entity}")
        
        # Initialize data containers
        all_normalized_data = []
        sources_used = []
        
        # Gather data from various sources concurrently
        tasks = []
        
        # IntelligenceX
        tasks.append(("intelx", search_intelx(entity)))
        
        # ENISA CVE
        tasks.append(("enisa_cve", fetch_enisa_cve(entity)))
        
        # VirusTotal
        tasks.append(("virustotal", search_virustotal(entity)))
        
        # Uncomment when ready to use
        # tasks.append(("shodan", search_shodan(entity)))
        # tasks.append(("maltego", fetch_from_maltego(entity)))
        
        # Execute all tasks concurrently
        results = {}
        for source_name, task in tasks:
            try:
                result = await task
                results[source_name] = result
                if result:  # Only add to sources if we got data
                    sources_used.append(source_name)
                logger.info(f"Successfully gathered data from {source_name}")
            except Exception as e:
                logger.error(f"Error gathering data from {source_name}: {str(e)}")
                results[source_name] = None
        
        # Normalize data from successful sources
        if results.get("intelx"):
            try:
                intelx_normalized = normalize_intelx_data(results["intelx"])
                all_normalized_data.extend(intelx_normalized)
            except Exception as e:
                logger.error(f"Error normalizing IntelX data: {str(e)}")
        
        if results.get("virustotal"):
            try:
                vt_normalized = normalize_virustotal_data(results["virustotal"])
                all_normalized_data.extend(vt_normalized)
            except Exception as e:
                logger.error(f"Error normalizing VirusTotal data: {str(e)}")
        
        # Uncomment when Shodan is ready
        # if results.get("shodan"):
        #     try:
        #         shodan_normalized = normalize_shodan_data(results["shodan"])
        #         all_normalized_data.extend(shodan_normalized)
        #     except Exception as e:
        #         logger.error(f"Error normalizing Shodan data: {str(e)}")
        
        # Check if we have any data to work with
        if not all_normalized_data and not results.get("enisa_cve"):
            raise HTTPException(
                status_code=404, 
                detail="No data found for the specified entity"
            )
        
        # Perform correlation analysis
        try:
            correlated_data = correlate_entities(results.get("enisa_cve", []), all_normalized_data)
            logger.info("Successfully correlated entity data")
        except Exception as e:
            logger.error(f"Error correlating data: {str(e)}")
            correlated_data = all_normalized_data
        
        # Assess risk
        try:
            risk_assessment = assess_risk(correlated_data)
            logger.info(f"Risk assessment completed: {risk_assessment}")
        except Exception as e:
            logger.error(f"Error assessing risk: {str(e)}")
            risk_assessment = {"level": "unknown", "confidence": 0.0}
        
        # Generate LLM summary
        try:
            llm = load_llm()
            prompt = get_summary_prompt(entity, correlated_data, risk_assessment)
            summary = await llm(prompt) if asyncio.iscoroutinefunction(llm) else llm(prompt)
            logger.info("Successfully generated LLM summary")
        except Exception as e:
            logger.error(f"Error generating LLM summary: {str(e)}")
            summary = f"Analysis completed for {entity}. Manual review recommended due to processing error."
        
        # Prepare response
        from datetime import datetime
        response = SummaryResponse(
            summary=summary,
            risk_level=risk_assessment.get("level", "unknown"),
            confidence=risk_assessment.get("confidence", 0.0),
            sources_used=sources_used,
            timestamp=datetime.utcnow().isoformat()
        )
        
        logger.info(f"OSINT analysis completed successfully for entity: {entity}")
        return response
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Unexpected error in OSINT analysis: {str(e)}")
        raise HTTPException(
            status_code=500,
            detail="Internal server error during analysis"
        )

@app.get("/api/sources")
async def get_available_sources():
    """Get list of available OSINT sources"""
    sources = [
        {"name": "IntelligenceX", "status": "active", "type": "threat_intelligence"},
        {"name": "ENISA CVE", "status": "active", "type": "vulnerability"},
        {"name": "VirusTotal", "status": "active", "type": "malware_analysis"},
        {"name": "Shodan", "status": "inactive", "type": "network_scanning"},
        {"name": "Maltego", "status": "inactive", "type": "graph_analysis"},
    ]
    return {"sources": sources}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000, log_level="info")