2023-11-24 14:57:32 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/csv"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"gopkg.in/yaml.v3"
|
|
|
|
"slices"
|
|
|
|
|
|
|
|
"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) {
|
|
|
|
itemNames := hub.GetItemNames(itemType)
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
items := make([]*cwhub.Item, 0, len(itemNames))
|
|
|
|
|
|
|
|
for _, itemName := range itemNames {
|
|
|
|
item := hub.GetItem(itemType, itemName)
|
|
|
|
if installedOnly && !item.State.Installed {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
items = append(items, item)
|
|
|
|
}
|
|
|
|
|
|
|
|
cwhub.SortItemSlice(items)
|
|
|
|
|
|
|
|
return items, nil
|
|
|
|
}
|
|
|
|
|
2023-12-05 12:38:52 +00:00
|
|
|
func listItems(out io.Writer, itemTypes []string, items map[string][]*cwhub.Item, omitIfEmpty bool) error {
|
2023-11-24 14:57:32 +00:00
|
|
|
switch csConfig.Cscli.Output {
|
|
|
|
case "human":
|
2023-12-05 12:38:52 +00:00
|
|
|
nothingToDisplay := true
|
2023-12-15 14:27:22 +00:00
|
|
|
|
2023-11-24 14:57:32 +00:00
|
|
|
for _, itemType := range itemTypes {
|
2023-12-05 12:38:52 +00:00
|
|
|
if omitIfEmpty && len(items[itemType]) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
2023-11-24 14:57:32 +00:00
|
|
|
listHubItemTable(out, "\n"+strings.ToUpper(itemType), items[itemType])
|
2023-12-05 12:38:52 +00:00
|
|
|
nothingToDisplay = false
|
|
|
|
}
|
2023-12-15 14:27:22 +00:00
|
|
|
|
2023-12-05 12:38:52 +00:00
|
|
|
if nothingToDisplay {
|
|
|
|
fmt.Println("No items to display")
|
2023-11-24 14:57:32 +00:00
|
|
|
}
|
|
|
|
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] {
|
2023-12-05 12:38:52 +00:00
|
|
|
status := item.State.Text()
|
2023-12-15 14:27:22 +00:00
|
|
|
statusEmo := item.State.Emoji()
|
2023-11-24 14:57:32 +00:00
|
|
|
hubStatus[itemType][i] = itemHubStatus{
|
|
|
|
Name: item.Name,
|
|
|
|
LocalVersion: item.State.LocalVersion,
|
|
|
|
LocalPath: item.State.LocalPath,
|
|
|
|
Description: item.Description,
|
|
|
|
Status: status,
|
2023-12-15 14:27:22 +00:00
|
|
|
UTF8Status: fmt.Sprintf("%v %s", statusEmo, status),
|
2023-11-24 14:57:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
x, err := json.MarshalIndent(hubStatus, "", " ")
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to unmarshal: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
out.Write(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: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, itemType := range itemTypes {
|
|
|
|
for _, item := range items[itemType] {
|
|
|
|
row := []string{
|
|
|
|
item.Name,
|
2023-12-05 12:38:52 +00:00
|
|
|
item.State.Text(),
|
2023-11-24 14:57:32 +00:00
|
|
|
item.State.LocalVersion,
|
|
|
|
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: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
csvwriter.Flush()
|
|
|
|
default:
|
|
|
|
return fmt.Errorf("unknown output format '%s'", csConfig.Cscli.Output)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func InspectItem(item *cwhub.Item, showMetrics bool) error {
|
|
|
|
switch csConfig.Cscli.Output {
|
|
|
|
case "human", "raw":
|
|
|
|
enc := yaml.NewEncoder(os.Stdout)
|
|
|
|
enc.SetIndent(2)
|
|
|
|
if err := enc.Encode(item); err != nil {
|
|
|
|
return fmt.Errorf("unable to encode item: %s", err)
|
|
|
|
}
|
|
|
|
case "json":
|
|
|
|
b, err := json.MarshalIndent(*item, "", " ")
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("unable to marshal item: %s", err)
|
|
|
|
}
|
|
|
|
fmt.Print(string(b))
|
|
|
|
}
|
|
|
|
|
|
|
|
if csConfig.Cscli.Output == "human" && showMetrics {
|
|
|
|
fmt.Printf("\nCurrent metrics: \n")
|
|
|
|
if err := ShowMetrics(item); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|