mirror of
https://github.com/andwati/telecom-platform.git
synced 2026-10-21 04:04:28 +00:00
- Add SecurityHandler with fraud analysis, alert filtering, and metrics endpoints - Add FraudAlert struct with ID, Type, Severity, ProfileID, RiskScore, Evidence, IPAddress, Status, and ActionsTaken fields - Add FraudMetrics struct with Period, TotalAlerts, ResolvedAlerts, ResolutionRate, FalsePositiveRate, ByType, and BySeverity fields - Add AnalyzeTransaction with risk scoring based on transaction amount and suspicious
315 lines
8.7 KiB
Go
315 lines
8.7 KiB
Go
package handlers
|
|
|
|
import (
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// SecurityHandler handles security-related HTTP requests
|
|
type SecurityHandler struct{}
|
|
|
|
// NewSecurityHandler creates a new security handler
|
|
func NewSecurityHandler() *SecurityHandler {
|
|
return &SecurityHandler{}
|
|
}
|
|
|
|
// FraudAlert represents a fraud alert
|
|
type FraudAlert struct {
|
|
ID string `json:"id"`
|
|
Type string `json:"type"`
|
|
Severity string `json:"severity"`
|
|
ProfileID string `json:"profile_id"`
|
|
Description string `json:"description"`
|
|
RiskScore float64 `json:"risk_score"`
|
|
Evidence []string `json:"evidence"`
|
|
IPAddress string `json:"ip_address"`
|
|
Timestamp time.Time `json:"timestamp"`
|
|
Status string `json:"status"`
|
|
ActionsTaken []string `json:"actions_taken"`
|
|
Metadata map[string]any `json:"metadata"`
|
|
}
|
|
|
|
// FraudMetrics represents fraud detection metrics
|
|
type FraudMetrics struct {
|
|
Period string `json:"period"`
|
|
TotalAlerts int64 `json:"total_alerts"`
|
|
ResolvedAlerts int64 `json:"resolved_alerts"`
|
|
FalsePositives int64 `json:"false_positives"`
|
|
ResolutionRate float64 `json:"resolution_rate_pct"`
|
|
FalsePositiveRate float64 `json:"false_positive_rate_pct"`
|
|
ByType map[string]int64 `json:"by_type"`
|
|
BySeverity map[string]int64 `json:"by_severity"`
|
|
GeneratedAt time.Time `json:"generated_at"`
|
|
}
|
|
|
|
// AnalyzeTransaction analyzes a transaction for fraud
|
|
func (h *SecurityHandler) AnalyzeTransaction(c *gin.Context) {
|
|
var req map[string]any
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
profileID, _ := req["profile_id"].(string)
|
|
ipAddress, _ := req["ip_address"].(string)
|
|
|
|
// Simulated fraud analysis
|
|
riskScore := 25.0 // Low risk by default
|
|
|
|
// Check for suspicious patterns
|
|
if amount, ok := req["amount"].(float64); ok && amount > 1000 {
|
|
riskScore += 20
|
|
}
|
|
|
|
alert := FraudAlert{
|
|
ID: "alert-" + time.Now().Format("20060102150405"),
|
|
Type: "transaction_analysis",
|
|
Severity: getSeverityFromScore(riskScore),
|
|
ProfileID: profileID,
|
|
Description: "Transaction analyzed for fraud indicators",
|
|
RiskScore: riskScore,
|
|
Evidence: []string{
|
|
"Transaction amount within normal range",
|
|
"IP address matches historical pattern",
|
|
"Device fingerprint recognized",
|
|
},
|
|
IPAddress: ipAddress,
|
|
Timestamp: time.Now(),
|
|
Status: "analyzed",
|
|
ActionsTaken: []string{"Logged for monitoring"},
|
|
Metadata: req,
|
|
}
|
|
|
|
c.JSON(http.StatusOK, alert)
|
|
}
|
|
|
|
// GetFraudAlerts returns fraud alerts with filtering
|
|
func (h *SecurityHandler) GetFraudAlerts(c *gin.Context) {
|
|
var filter struct {
|
|
Type string `json:"type"`
|
|
Severity string `json:"severity"`
|
|
Status string `json:"status"`
|
|
Limit int `json:"limit"`
|
|
}
|
|
c.ShouldBindJSON(&filter)
|
|
|
|
if filter.Limit == 0 || filter.Limit > 100 {
|
|
filter.Limit = 50
|
|
}
|
|
|
|
// Simulated alerts
|
|
alerts := []FraudAlert{
|
|
{
|
|
ID: "alert-001",
|
|
Type: "account_takeover",
|
|
Severity: "high",
|
|
ProfileID: "profile-123",
|
|
Description: "Multiple failed login attempts from new IP",
|
|
RiskScore: 85.0,
|
|
Evidence: []string{"10 failed logins", "New IP address", "Different country"},
|
|
IPAddress: "192.168.1.100",
|
|
Timestamp: time.Now().Add(-2 * time.Hour),
|
|
Status: "new",
|
|
},
|
|
{
|
|
ID: "alert-002",
|
|
Type: "payment_fraud",
|
|
Severity: "medium",
|
|
ProfileID: "profile-456",
|
|
Description: "Unusual payment pattern detected",
|
|
RiskScore: 55.0,
|
|
Evidence: []string{"Large transaction", "New payment method"},
|
|
IPAddress: "10.0.0.50",
|
|
Timestamp: time.Now().Add(-5 * time.Hour),
|
|
Status: "investigating",
|
|
},
|
|
{
|
|
ID: "alert-003",
|
|
Type: "sim_swap",
|
|
Severity: "critical",
|
|
ProfileID: "profile-789",
|
|
Description: "SIM swap attempt detected",
|
|
RiskScore: 95.0,
|
|
Evidence: []string{"SIM change request", "No prior notification", "High-value account"},
|
|
IPAddress: "172.16.0.25",
|
|
Timestamp: time.Now().Add(-30 * time.Minute),
|
|
Status: "blocked",
|
|
},
|
|
}
|
|
|
|
// Filter alerts
|
|
filtered := make([]FraudAlert, 0)
|
|
for _, alert := range alerts {
|
|
if filter.Type != "" && alert.Type != filter.Type {
|
|
continue
|
|
}
|
|
if filter.Severity != "" && alert.Severity != filter.Severity {
|
|
continue
|
|
}
|
|
if filter.Status != "" && alert.Status != filter.Status {
|
|
continue
|
|
}
|
|
filtered = append(filtered, alert)
|
|
if len(filtered) >= filter.Limit {
|
|
break
|
|
}
|
|
}
|
|
|
|
c.JSON(http.StatusOK, filtered)
|
|
}
|
|
|
|
// UpdateAlertStatus updates a fraud alert status
|
|
func (h *SecurityHandler) UpdateAlertStatus(c *gin.Context) {
|
|
alertID := c.Param("id")
|
|
|
|
var req struct {
|
|
Status string `json:"status" binding:"required"`
|
|
Actions []string `json:"actions"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"id": alertID,
|
|
"status": req.Status,
|
|
"actions_taken": req.Actions,
|
|
"updated_at": time.Now(),
|
|
})
|
|
}
|
|
|
|
// GetFraudMetrics returns fraud detection metrics
|
|
func (h *SecurityHandler) GetFraudMetrics(c *gin.Context) {
|
|
period := c.DefaultQuery("period", "monthly")
|
|
|
|
metrics := FraudMetrics{
|
|
Period: period,
|
|
TotalAlerts: 1250,
|
|
ResolvedAlerts: 1100,
|
|
FalsePositives: 125,
|
|
ResolutionRate: 88.0,
|
|
FalsePositiveRate: 10.0,
|
|
ByType: map[string]int64{
|
|
"account_takeover": 350,
|
|
"subscription_fraud": 200,
|
|
"payment_fraud": 400,
|
|
"usage_anomaly": 200,
|
|
"sim_swap": 100,
|
|
},
|
|
BySeverity: map[string]int64{
|
|
"low": 400,
|
|
"medium": 500,
|
|
"high": 250,
|
|
"critical": 100,
|
|
},
|
|
GeneratedAt: time.Now(),
|
|
}
|
|
|
|
c.JSON(http.StatusOK, metrics)
|
|
}
|
|
|
|
// GetFraudPatterns returns detected fraud patterns
|
|
func (h *SecurityHandler) GetFraudPatterns(c *gin.Context) {
|
|
patterns := []map[string]any{
|
|
{
|
|
"id": "pattern-1",
|
|
"name": "Velocity Attack",
|
|
"description": "Multiple rapid transactions from same source",
|
|
"frequency": "high",
|
|
"indicators": []string{"High transaction rate", "Same IP", "Different accounts"},
|
|
"mitigation": "Rate limiting, IP blocking",
|
|
},
|
|
{
|
|
"id": "pattern-2",
|
|
"name": "Account Enumeration",
|
|
"description": "Systematic probing of account existence",
|
|
"frequency": "medium",
|
|
"indicators": []string{"Sequential account checks", "Automated requests"},
|
|
"mitigation": "CAPTCHA, rate limiting",
|
|
},
|
|
{
|
|
"id": "pattern-3",
|
|
"name": "SIM Swap Attack",
|
|
"description": "Unauthorized SIM card replacement",
|
|
"frequency": "low",
|
|
"indicators": []string{"Sudden SIM change", "No customer contact", "High-value target"},
|
|
"mitigation": "Multi-factor verification, cooling period",
|
|
},
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"patterns": patterns})
|
|
}
|
|
|
|
// VerifySIMSwap verifies a SIM swap request
|
|
func (h *SecurityHandler) VerifySIMSwap(c *gin.Context) {
|
|
var req struct {
|
|
ProfileID string `json:"profile_id" binding:"required"`
|
|
MSISDN string `json:"msisdn" binding:"required"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
// Simulated SIM swap verification
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"profile_id": req.ProfileID,
|
|
"msisdn": req.MSISDN,
|
|
"verified": true,
|
|
"risk_score": 15.0,
|
|
"risk_level": "low",
|
|
"last_sim_swap": time.Now().AddDate(-1, 0, 0).Format("2006-01-02"),
|
|
"checks_passed": []string{
|
|
"Identity verified",
|
|
"No recent SIM changes",
|
|
"Account in good standing",
|
|
},
|
|
})
|
|
}
|
|
|
|
// GetSIMSwapHistory returns SIM swap history for a profile
|
|
func (h *SecurityHandler) GetSIMSwapHistory(c *gin.Context) {
|
|
profileID := c.Param("profile_id")
|
|
|
|
history := []map[string]any{
|
|
{
|
|
"id": "swap-001",
|
|
"profile_id": profileID,
|
|
"old_iccid": "8901234567890123456",
|
|
"new_iccid": "8901234567890123457",
|
|
"timestamp": time.Now().AddDate(-1, 0, 0),
|
|
"reason": "Device upgrade",
|
|
"verified": true,
|
|
"status": "completed",
|
|
},
|
|
{
|
|
"id": "swap-002",
|
|
"profile_id": profileID,
|
|
"old_iccid": "8901234567890123455",
|
|
"new_iccid": "8901234567890123456",
|
|
"timestamp": time.Now().AddDate(-2, 0, 0),
|
|
"reason": "Lost device",
|
|
"verified": true,
|
|
"status": "completed",
|
|
},
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"history": history})
|
|
}
|
|
|
|
func getSeverityFromScore(score float64) string {
|
|
switch {
|
|
case score >= 80:
|
|
return "critical"
|
|
case score >= 60:
|
|
return "high"
|
|
case score >= 40:
|
|
return "medium"
|
|
default:
|
|
return "low"
|
|
}
|
|
}
|