88e4f7c157
* csconfig: drop redundant hub information on *Cfg structs * rename validItemFileName() -> item.validPath() * Methods on hub object * updated tests to reduce need of csconfig.Config or global state
228 lines
5.5 KiB
Go
228 lines
5.5 KiB
Go
package cwhub
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
|
|
"github.com/enescakir/emoji"
|
|
log "github.com/sirupsen/logrus"
|
|
"golang.org/x/mod/semver"
|
|
|
|
"github.com/crowdsecurity/crowdsec/pkg/cwversion"
|
|
)
|
|
|
|
// chooseHubBranch returns the branch name to use for the hub
|
|
// It can be "master" or branch corresponding to the current crowdsec version
|
|
func chooseHubBranch() string {
|
|
latest, err := cwversion.Latest()
|
|
if err != nil {
|
|
log.Warningf("Unable to retrieve latest crowdsec version: %s, defaulting to master", err)
|
|
return "master"
|
|
}
|
|
|
|
csVersion := cwversion.VersionStrip()
|
|
if csVersion == latest {
|
|
log.Debugf("current version is equal to latest (%s)", csVersion)
|
|
return "master"
|
|
}
|
|
|
|
// if current version is greater than the latest we are in pre-release
|
|
if semver.Compare(csVersion, latest) == 1 {
|
|
log.Debugf("Your current crowdsec version seems to be a pre-release (%s)", csVersion)
|
|
return "master"
|
|
}
|
|
|
|
if csVersion == "" {
|
|
log.Warning("Crowdsec version is not set, using master branch for the hub")
|
|
return "master"
|
|
}
|
|
|
|
log.Warnf("Crowdsec is not the latest version. "+
|
|
"Current version is '%s' and the latest stable version is '%s'. Please update it!",
|
|
csVersion, latest)
|
|
|
|
log.Warnf("As a result, you will not be able to use parsers/scenarios/collections "+
|
|
"added to Crowdsec Hub after CrowdSec %s", latest)
|
|
|
|
return csVersion
|
|
}
|
|
|
|
// SetHubBranch sets the package variable that points to the hub branch.
|
|
func SetHubBranch() {
|
|
// a branch is already set, or specified from the flags
|
|
if HubBranch != "" {
|
|
return
|
|
}
|
|
|
|
// use the branch corresponding to the crowdsec version
|
|
HubBranch = chooseHubBranch()
|
|
|
|
log.Debugf("Using branch '%s' for the hub", HubBranch)
|
|
}
|
|
|
|
// InstallItem installs an item from the hub
|
|
func (h *Hub) InstallItem(name string, itemType string, force bool, downloadOnly bool) error {
|
|
item := h.GetItem(itemType, name)
|
|
if item == nil {
|
|
return fmt.Errorf("unable to retrieve item: %s", name)
|
|
}
|
|
|
|
if downloadOnly && item.Downloaded && item.UpToDate {
|
|
log.Warningf("%s is already downloaded and up-to-date", item.Name)
|
|
|
|
if !force {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
err := h.DownloadLatest(item, force, true)
|
|
if err != nil {
|
|
return fmt.Errorf("while downloading %s: %w", item.Name, err)
|
|
}
|
|
|
|
if err = h.AddItem(itemType, *item); err != nil {
|
|
return fmt.Errorf("while adding %s: %w", item.Name, err)
|
|
}
|
|
|
|
if downloadOnly {
|
|
log.Infof("Downloaded %s to %s", item.Name, filepath.Join(h.cfg.HubDir, item.RemotePath))
|
|
return nil
|
|
}
|
|
|
|
err = h.EnableItem(item)
|
|
if err != nil {
|
|
return fmt.Errorf("while enabling %s: %w", item.Name, err)
|
|
}
|
|
|
|
if err := h.AddItem(itemType, *item); err != nil {
|
|
return fmt.Errorf("while adding %s: %w", item.Name, err)
|
|
}
|
|
|
|
log.Infof("Enabled %s", item.Name)
|
|
|
|
return nil
|
|
}
|
|
|
|
// RemoveItem removes one - or all - the items from the hub
|
|
func (h *Hub) RemoveMany(itemType string, name string, all bool, purge bool, forceAction bool) error {
|
|
if name != "" {
|
|
item := h.GetItem(itemType, name)
|
|
if item == nil {
|
|
return fmt.Errorf("can't find '%s' in %s", name, itemType)
|
|
}
|
|
|
|
err := h.DisableItem(item, purge, forceAction)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("unable to disable %s: %w", item.Name, err)
|
|
}
|
|
|
|
if err = h.AddItem(itemType, *item); err != nil {
|
|
return fmt.Errorf("unable to add %s: %w", item.Name, err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
if !all {
|
|
return fmt.Errorf("removing item: no item specified")
|
|
}
|
|
|
|
disabled := 0
|
|
|
|
// remove all
|
|
for _, v := range h.GetItemMap(itemType) {
|
|
if !v.Installed {
|
|
continue
|
|
}
|
|
|
|
err := h.DisableItem(&v, purge, forceAction)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to disable %s: %w", v.Name, err)
|
|
}
|
|
|
|
if err := h.AddItem(itemType, v); err != nil {
|
|
return fmt.Errorf("unable to add %s: %w", v.Name, err)
|
|
}
|
|
disabled++
|
|
}
|
|
|
|
log.Infof("Disabled %d items", disabled)
|
|
|
|
return nil
|
|
}
|
|
|
|
// UpgradeConfig upgrades an item from the hub
|
|
func (h *Hub) UpgradeConfig(itemType string, name string, force bool) error {
|
|
updated := 0
|
|
found := false
|
|
|
|
for _, v := range h.GetItemMap(itemType) {
|
|
if name != "" && name != v.Name {
|
|
continue
|
|
}
|
|
|
|
if !v.Installed {
|
|
log.Tracef("skip %s, not installed", v.Name)
|
|
continue
|
|
}
|
|
|
|
if !v.Downloaded {
|
|
log.Warningf("%s: not downloaded, please install.", v.Name)
|
|
continue
|
|
}
|
|
|
|
found = true
|
|
|
|
if v.UpToDate {
|
|
log.Infof("%s: up-to-date", v.Name)
|
|
|
|
if err := h.DownloadDataIfNeeded(v, force); err != nil {
|
|
return fmt.Errorf("%s: download failed: %w", v.Name, err)
|
|
}
|
|
|
|
if !force {
|
|
continue
|
|
}
|
|
}
|
|
|
|
if err := h.DownloadLatest(&v, force, true); err != nil {
|
|
return fmt.Errorf("%s: download failed: %w", v.Name, err)
|
|
}
|
|
|
|
if !v.UpToDate {
|
|
if v.Tainted {
|
|
log.Infof("%v %s is tainted, --force to overwrite", emoji.Warning, v.Name)
|
|
} else if v.Local {
|
|
log.Infof("%v %s is local", emoji.Prohibited, v.Name)
|
|
}
|
|
} else {
|
|
// this is used while scripting to know if the hub has been upgraded
|
|
// and a configuration reload is required
|
|
fmt.Printf("updated %s\n", v.Name)
|
|
log.Infof("%v %s : updated", emoji.Package, v.Name)
|
|
updated++
|
|
}
|
|
|
|
if err := h.AddItem(itemType, v); err != nil {
|
|
return fmt.Errorf("unable to add %s: %w", v.Name, err)
|
|
}
|
|
}
|
|
|
|
if !found && name == "" {
|
|
log.Infof("No %s installed, nothing to upgrade", itemType)
|
|
} else if !found {
|
|
log.Errorf("can't find '%s' in %s", name, itemType)
|
|
} else if updated == 0 && found {
|
|
if name == "" {
|
|
log.Infof("All %s are already up-to-date", itemType)
|
|
} else {
|
|
log.Infof("Item '%s' is up-to-date", name)
|
|
}
|
|
} else if updated != 0 {
|
|
log.Infof("Upgraded %d items", updated)
|
|
}
|
|
|
|
return nil
|
|
}
|