package clihub import ( "encoding/csv" "encoding/json" "fmt" "io" "slices" "strings" "github.com/crowdsecurity/crowdsec/pkg/cwhub" ) // selectItems returns a slice of items of a given type, selected by name and sorted by case-insensitive name func SelectItems(hub *cwhub.Hub, itemType string, args []string, installedOnly bool) ([]*cwhub.Item, error) { allItems := hub.GetItemsByType(itemType, true) itemNames := make([]string, len(allItems)) for idx, item := range allItems { itemNames[idx] = item.Name } notExist := []string{} if len(args) > 0 { for _, arg := range args { if !slices.Contains(itemNames, arg) { notExist = append(notExist, arg) } } } if len(notExist) > 0 { return nil, fmt.Errorf("item(s) '%s' not found in %s", strings.Join(notExist, ", "), itemType) } if len(args) > 0 { itemNames = args installedOnly = false } wantedItems := make([]*cwhub.Item, 0, len(itemNames)) for _, itemName := range itemNames { item := hub.GetItem(itemType, itemName) if installedOnly && !item.State.IsInstalled() { continue } wantedItems = append(wantedItems, item) } return wantedItems, nil } func ListItems(out io.Writer, wantColor string, itemTypes []string, items map[string][]*cwhub.Item, omitIfEmpty bool, output string) error { switch output { case "human": nothingToDisplay := true for _, itemType := range itemTypes { if omitIfEmpty && len(items[itemType]) == 0 { continue } listHubItemTable(out, wantColor, strings.ToUpper(itemType), items[itemType]) nothingToDisplay = false } if nothingToDisplay { fmt.Println("No items to display") } case "json": type itemHubStatus struct { Name string `json:"name"` LocalVersion string `json:"local_version"` LocalPath string `json:"local_path"` Description string `json:"description"` UTF8Status string `json:"utf8_status"` Status string `json:"status"` } hubStatus := make(map[string][]itemHubStatus) for _, itemType := range itemTypes { // empty slice in case there are no items of this type hubStatus[itemType] = make([]itemHubStatus, len(items[itemType])) for i, item := range items[itemType] { status := item.State.Text() statusEmo := item.State.Emoji() hubStatus[itemType][i] = itemHubStatus{ Name: item.Name, LocalVersion: item.State.LocalVersion, LocalPath: item.State.LocalPath, Description: strings.TrimSpace(item.Description), Status: status, UTF8Status: fmt.Sprintf("%v %s", statusEmo, status), } } } x, err := json.MarshalIndent(hubStatus, "", " ") if err != nil { return fmt.Errorf("failed to parse: %w", err) } fmt.Fprint(out, string(x)) case "raw": csvwriter := csv.NewWriter(out) header := []string{"name", "status", "version", "description"} if len(itemTypes) > 1 { header = append(header, "type") } if err := csvwriter.Write(header); err != nil { return fmt.Errorf("failed to write header: %w", err) } for _, itemType := range itemTypes { for _, item := range items[itemType] { row := []string{ item.Name, item.State.Text(), item.State.LocalVersion, strings.TrimSpace(item.Description), } if len(itemTypes) > 1 { row = append(row, itemType) } if err := csvwriter.Write(row); err != nil { return fmt.Errorf("failed to write raw output: %w", err) } } } csvwriter.Flush() } return nil }