mirror of
https://github.com/yyhuni/xingrin.git
synced 2026-01-31 11:46:16 +08:00
完成target资产统计count
This commit is contained in:
@@ -33,6 +33,8 @@ export interface TargetDetail extends Target {
|
||||
websites: number
|
||||
endpoints: number
|
||||
ips: number
|
||||
directories: number
|
||||
screenshots: number
|
||||
vulnerabilities: {
|
||||
total: number
|
||||
critical: number
|
||||
|
||||
@@ -69,3 +69,34 @@ type BulkDeleteRequest struct {
|
||||
type BulkDeleteResponse struct {
|
||||
DeletedCount int64 `json:"deletedCount"`
|
||||
}
|
||||
|
||||
// TargetDetailResponse represents target detail response with summary
|
||||
type TargetDetailResponse struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
LastScannedAt *time.Time `json:"lastScannedAt"`
|
||||
Organizations []OrganizationBrief `json:"organizations,omitempty"`
|
||||
Summary *TargetSummary `json:"summary"`
|
||||
}
|
||||
|
||||
// TargetSummary represents target asset statistics
|
||||
type TargetSummary struct {
|
||||
Subdomains int64 `json:"subdomains"`
|
||||
Websites int64 `json:"websites"`
|
||||
Endpoints int64 `json:"endpoints"`
|
||||
IPs int64 `json:"ips"`
|
||||
Directories int64 `json:"directories"`
|
||||
Screenshots int64 `json:"screenshots"`
|
||||
Vulnerabilities *VulnerabilitySummary `json:"vulnerabilities"`
|
||||
}
|
||||
|
||||
// VulnerabilitySummary represents vulnerability statistics by severity
|
||||
type VulnerabilitySummary struct {
|
||||
Total int64 `json:"total"`
|
||||
Critical int64 `json:"critical"`
|
||||
High int64 `json:"high"`
|
||||
Medium int64 `json:"medium"`
|
||||
Low int64 `json:"low"`
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ func (h *TargetHandler) GetByID(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
target, err := h.svc.GetByID(id)
|
||||
target, summary, err := h.svc.GetDetailByID(id)
|
||||
if err != nil {
|
||||
if errors.Is(err, service.ErrTargetNotFound) {
|
||||
dto.NotFound(c, "Target not found")
|
||||
@@ -107,12 +107,13 @@ func (h *TargetHandler) GetByID(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
dto.Success(c, dto.TargetResponse{
|
||||
dto.Success(c, dto.TargetDetailResponse{
|
||||
ID: target.ID,
|
||||
Name: target.Name,
|
||||
Type: target.Type,
|
||||
CreatedAt: target.CreatedAt,
|
||||
LastScannedAt: target.LastScannedAt,
|
||||
Summary: summary,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -141,3 +141,114 @@ func (r *TargetRepository) FindByNames(names []string) ([]model.Target, error) {
|
||||
Find(&targets).Error
|
||||
return targets, err
|
||||
}
|
||||
|
||||
// TargetAssetCounts holds asset count statistics for a target
|
||||
type TargetAssetCounts struct {
|
||||
Subdomains int64
|
||||
Websites int64
|
||||
Endpoints int64
|
||||
IPs int64
|
||||
Directories int64
|
||||
Screenshots int64
|
||||
}
|
||||
|
||||
// VulnerabilityCounts holds vulnerability count statistics by severity
|
||||
type VulnerabilityCounts struct {
|
||||
Total int64
|
||||
Critical int64
|
||||
High int64
|
||||
Medium int64
|
||||
Low int64
|
||||
}
|
||||
|
||||
// GetAssetCounts returns asset counts for a target
|
||||
func (r *TargetRepository) GetAssetCounts(targetID int) (*TargetAssetCounts, error) {
|
||||
counts := &TargetAssetCounts{}
|
||||
|
||||
// Count subdomains
|
||||
if err := r.db.Table("subdomain").
|
||||
Where("target_id = ?", targetID).
|
||||
Count(&counts.Subdomains).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Count websites
|
||||
if err := r.db.Table("website").
|
||||
Where("target_id = ?", targetID).
|
||||
Count(&counts.Websites).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Count endpoints
|
||||
if err := r.db.Table("endpoint").
|
||||
Where("target_id = ?", targetID).
|
||||
Count(&counts.Endpoints).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Count distinct IPs from host_port_mapping
|
||||
if err := r.db.Table("host_port_mapping").
|
||||
Where("target_id = ?", targetID).
|
||||
Select("COUNT(DISTINCT ip)").
|
||||
Scan(&counts.IPs).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Count directories
|
||||
if err := r.db.Table("directory").
|
||||
Where("target_id = ?", targetID).
|
||||
Count(&counts.Directories).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Count screenshots
|
||||
if err := r.db.Table("screenshot").
|
||||
Where("target_id = ?", targetID).
|
||||
Count(&counts.Screenshots).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return counts, nil
|
||||
}
|
||||
|
||||
// GetVulnerabilityCounts returns vulnerability counts by severity for a target
|
||||
func (r *TargetRepository) GetVulnerabilityCounts(targetID int) (*VulnerabilityCounts, error) {
|
||||
counts := &VulnerabilityCounts{}
|
||||
|
||||
// Count total vulnerabilities
|
||||
if err := r.db.Table("vulnerability").
|
||||
Where("target_id = ?", targetID).
|
||||
Count(&counts.Total).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Count by severity
|
||||
type severityCount struct {
|
||||
Severity string
|
||||
Count int64
|
||||
}
|
||||
var severityCounts []severityCount
|
||||
|
||||
if err := r.db.Table("vulnerability").
|
||||
Select("severity, COUNT(*) as count").
|
||||
Where("target_id = ?", targetID).
|
||||
Group("severity").
|
||||
Scan(&severityCounts).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, sc := range severityCounts {
|
||||
switch sc.Severity {
|
||||
case "critical":
|
||||
counts.Critical = sc.Count
|
||||
case "high":
|
||||
counts.High = sc.Count
|
||||
case "medium":
|
||||
counts.Medium = sc.Count
|
||||
case "low":
|
||||
counts.Low = sc.Count
|
||||
}
|
||||
}
|
||||
|
||||
return counts, nil
|
||||
}
|
||||
|
||||
@@ -73,6 +73,47 @@ func (s *TargetService) GetByID(id int) (*model.Target, error) {
|
||||
return target, nil
|
||||
}
|
||||
|
||||
// GetDetailByID returns a target with asset summary by ID
|
||||
func (s *TargetService) GetDetailByID(id int) (*model.Target, *dto.TargetSummary, error) {
|
||||
target, err := s.repo.FindByID(id)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil, ErrTargetNotFound
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Get asset counts
|
||||
assetCounts, err := s.repo.GetAssetCounts(id)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Get vulnerability counts
|
||||
vulnCounts, err := s.repo.GetVulnerabilityCounts(id)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
summary := &dto.TargetSummary{
|
||||
Subdomains: assetCounts.Subdomains,
|
||||
Websites: assetCounts.Websites,
|
||||
Endpoints: assetCounts.Endpoints,
|
||||
IPs: assetCounts.IPs,
|
||||
Directories: assetCounts.Directories,
|
||||
Screenshots: assetCounts.Screenshots,
|
||||
Vulnerabilities: &dto.VulnerabilitySummary{
|
||||
Total: vulnCounts.Total,
|
||||
Critical: vulnCounts.Critical,
|
||||
High: vulnCounts.High,
|
||||
Medium: vulnCounts.Medium,
|
||||
Low: vulnCounts.Low,
|
||||
},
|
||||
}
|
||||
|
||||
return target, summary, nil
|
||||
}
|
||||
|
||||
// Update updates a target
|
||||
func (s *TargetService) Update(id int, req *dto.UpdateTargetRequest) (*model.Target, error) {
|
||||
target, err := s.repo.FindByID(id)
|
||||
|
||||
Reference in New Issue
Block a user