mirror of
https://github.com/j3ssie/osmedeus.git
synced 2026-08-31 12:19:50 +02:00
266 lines
7.7 KiB
Go
266 lines
7.7 KiB
Go
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/j3ssie/osmedeus/v5/internal/config"
|
|
"github.com/j3ssie/osmedeus/v5/internal/database"
|
|
)
|
|
|
|
// GetAssetDiff returns the diff between two time points for assets
|
|
// @Summary Get asset diff
|
|
// @Description Compare assets between two time points to find added, removed, and changed assets
|
|
// @Tags Assets
|
|
// @Produce json
|
|
// @Param workspace query string true "Workspace name"
|
|
// @Param from query string true "Start time (RFC3339 format or Unix timestamp)"
|
|
// @Param to query string false "End time (default: now)"
|
|
// @Success 200 {object} map[string]interface{} "Asset diff result"
|
|
// @Failure 400 {object} map[string]interface{} "Invalid parameters"
|
|
// @Failure 500 {object} map[string]interface{} "Failed to get asset diff"
|
|
// @Security BearerAuth
|
|
// @Router /osm/api/assets/diff [get]
|
|
func GetAssetDiff(cfg *config.Config) fiber.Handler {
|
|
return func(c *fiber.Ctx) error {
|
|
workspace := c.Query("workspace")
|
|
if workspace == "" {
|
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
|
"error": true,
|
|
"message": "workspace parameter is required",
|
|
})
|
|
}
|
|
|
|
fromStr := c.Query("from")
|
|
if fromStr == "" {
|
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
|
"error": true,
|
|
"message": "from parameter is required",
|
|
})
|
|
}
|
|
|
|
fromTime, err := parseTime(fromStr)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
|
"error": true,
|
|
"message": fmt.Sprintf("invalid from time format: %v", err),
|
|
})
|
|
}
|
|
|
|
toTime := time.Now()
|
|
if toStr := c.Query("to"); toStr != "" {
|
|
toTime, err = parseTime(toStr)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
|
"error": true,
|
|
"message": fmt.Sprintf("invalid to time format: %v", err),
|
|
})
|
|
}
|
|
}
|
|
|
|
ctx := context.Background()
|
|
diff, err := database.GetAssetDiff(ctx, workspace, fromTime, toTime)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": true,
|
|
"message": err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"data": diff,
|
|
})
|
|
}
|
|
}
|
|
|
|
// GetVulnerabilityDiff returns the diff between two time points for vulnerabilities
|
|
// @Summary Get vulnerability diff
|
|
// @Description Compare vulnerabilities between two time points to find added, removed, and changed vulnerabilities
|
|
// @Tags Vulnerabilities
|
|
// @Produce json
|
|
// @Param workspace query string true "Workspace name"
|
|
// @Param from query string true "Start time (RFC3339 format or Unix timestamp)"
|
|
// @Param to query string false "End time (default: now)"
|
|
// @Success 200 {object} map[string]interface{} "Vulnerability diff result"
|
|
// @Failure 400 {object} map[string]interface{} "Invalid parameters"
|
|
// @Failure 500 {object} map[string]interface{} "Failed to get vulnerability diff"
|
|
// @Security BearerAuth
|
|
// @Router /osm/api/vulnerabilities/diff [get]
|
|
func GetVulnerabilityDiff(cfg *config.Config) fiber.Handler {
|
|
return func(c *fiber.Ctx) error {
|
|
workspace := c.Query("workspace")
|
|
if workspace == "" {
|
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
|
"error": true,
|
|
"message": "workspace parameter is required",
|
|
})
|
|
}
|
|
|
|
fromStr := c.Query("from")
|
|
if fromStr == "" {
|
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
|
"error": true,
|
|
"message": "from parameter is required",
|
|
})
|
|
}
|
|
|
|
fromTime, err := parseTime(fromStr)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
|
"error": true,
|
|
"message": fmt.Sprintf("invalid from time format: %v", err),
|
|
})
|
|
}
|
|
|
|
toTime := time.Now()
|
|
if toStr := c.Query("to"); toStr != "" {
|
|
toTime, err = parseTime(toStr)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
|
"error": true,
|
|
"message": fmt.Sprintf("invalid to time format: %v", err),
|
|
})
|
|
}
|
|
}
|
|
|
|
ctx := context.Background()
|
|
diff, err := database.GetVulnerabilityDiff(ctx, workspace, fromTime, toTime)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": true,
|
|
"message": err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"data": diff,
|
|
})
|
|
}
|
|
}
|
|
|
|
// ListAssetDiffSnapshots handles listing stored asset diff snapshots
|
|
// @Summary List asset diff snapshots
|
|
// @Description Get a paginated list of stored asset diff snapshots
|
|
// @Tags Assets
|
|
// @Produce json
|
|
// @Param workspace query string false "Filter by workspace name"
|
|
// @Param offset query int false "Number of records to skip" default(0)
|
|
// @Param limit query int false "Maximum number of records to return" default(20)
|
|
// @Success 200 {object} map[string]interface{} "List of asset diff snapshots with pagination"
|
|
// @Failure 500 {object} map[string]interface{} "Failed to fetch asset diff snapshots"
|
|
// @Security BearerAuth
|
|
// @Router /osm/api/assets/diffs [get]
|
|
func ListAssetDiffSnapshots(cfg *config.Config) fiber.Handler {
|
|
return func(c *fiber.Ctx) error {
|
|
workspace := c.Query("workspace")
|
|
offset, _ := strconv.Atoi(c.Query("offset", "0"))
|
|
limit, _ := strconv.Atoi(c.Query("limit", "20"))
|
|
|
|
if offset < 0 {
|
|
offset = 0
|
|
}
|
|
if limit <= 0 {
|
|
limit = 20
|
|
}
|
|
if limit > 10000 {
|
|
limit = 10000
|
|
}
|
|
|
|
ctx := context.Background()
|
|
result, err := database.ListAssetDiffSnapshots(ctx, workspace, offset, limit)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": true,
|
|
"message": err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"data": result.Data,
|
|
"pagination": fiber.Map{
|
|
"total": result.TotalCount,
|
|
"offset": result.Offset,
|
|
"limit": result.Limit,
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
// ListVulnDiffSnapshots handles listing stored vulnerability diff snapshots
|
|
// @Summary List vulnerability diff snapshots
|
|
// @Description Get a paginated list of stored vulnerability diff snapshots
|
|
// @Tags Vulnerabilities
|
|
// @Produce json
|
|
// @Param workspace query string false "Filter by workspace name"
|
|
// @Param offset query int false "Number of records to skip" default(0)
|
|
// @Param limit query int false "Maximum number of records to return" default(20)
|
|
// @Success 200 {object} map[string]interface{} "List of vulnerability diff snapshots with pagination"
|
|
// @Failure 500 {object} map[string]interface{} "Failed to fetch vulnerability diff snapshots"
|
|
// @Security BearerAuth
|
|
// @Router /osm/api/vulnerabilities/diffs [get]
|
|
func ListVulnDiffSnapshots(cfg *config.Config) fiber.Handler {
|
|
return func(c *fiber.Ctx) error {
|
|
workspace := c.Query("workspace")
|
|
offset, _ := strconv.Atoi(c.Query("offset", "0"))
|
|
limit, _ := strconv.Atoi(c.Query("limit", "20"))
|
|
|
|
if offset < 0 {
|
|
offset = 0
|
|
}
|
|
if limit <= 0 {
|
|
limit = 20
|
|
}
|
|
if limit > 10000 {
|
|
limit = 10000
|
|
}
|
|
|
|
ctx := context.Background()
|
|
result, err := database.ListVulnDiffSnapshots(ctx, workspace, offset, limit)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
"error": true,
|
|
"message": err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"data": result.Data,
|
|
"pagination": fiber.Map{
|
|
"total": result.TotalCount,
|
|
"offset": result.Offset,
|
|
"limit": result.Limit,
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
// parseTime parses a time string in RFC3339 format or Unix timestamp
|
|
func parseTime(s string) (time.Time, error) {
|
|
// Try RFC3339 first
|
|
if t, err := time.Parse(time.RFC3339, s); err == nil {
|
|
return t, nil
|
|
}
|
|
|
|
// Try Unix timestamp (seconds)
|
|
if ts, err := strconv.ParseInt(s, 10, 64); err == nil {
|
|
return time.Unix(ts, 0), nil
|
|
}
|
|
|
|
// Try common date formats
|
|
formats := []string{
|
|
"2006-01-02T15:04:05",
|
|
"2006-01-02 15:04:05",
|
|
"2006-01-02",
|
|
}
|
|
for _, format := range formats {
|
|
if t, err := time.Parse(format, s); err == nil {
|
|
return t, nil
|
|
}
|
|
}
|
|
|
|
return time.Time{}, fmt.Errorf("invalid time format, use RFC3339 or Unix timestamp")
|
|
}
|