package collector import ( "os/exec" "strings" ) type Plugin struct { Name string `json:"name"` Version string `json:"version"` Description string `json:"description"` } // CollectPlugins liest installierte OPNsense Plugins via pkg info func CollectPlugins() []Plugin { out, err := exec.Command("/usr/sbin/pkg", "info").Output() if err != nil { return nil } var plugins []Plugin for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") { if line == "" { continue } // Nur os-* Pakete sind OPNsense Plugins if !strings.HasPrefix(line, "os-") { continue } // Format: "os-acme-client-4.13 ACME Client" // Erste Spalte: Name-Version, Rest: Beschreibung fields := strings.Fields(line) if len(fields) < 2 { continue } nameVer := fields[0] desc := strings.Join(fields[1:], " ") // Name und Version trennen: letztes "-" vor einer Ziffer ist der Trenner name, version := splitNameVersion(nameVer) plugins = append(plugins, Plugin{ Name: name, Version: version, Description: desc, }) } return plugins } // splitNameVersion trennt "os-acme-client-4.13" in ("os-acme-client", "4.13") func splitNameVersion(s string) (string, string) { // Von hinten suchen: letztes "-" gefolgt von einer Ziffer for i := len(s) - 1; i >= 0; i-- { if s[i] == '-' && i+1 < len(s) && s[i+1] >= '0' && s[i+1] <= '9' { return s[:i], s[i+1:] } } return s, "" }