1package cmd 2 3import ( 4 "fmt" 5 6 "github.com/BurntSushi/toml" 7 "github.com/inconshreveable/log15" 8 9 "github.com/knqyf263/gost/config" 10 "github.com/knqyf263/gost/db" 11 "github.com/knqyf263/gost/fetcher" 12 "github.com/knqyf263/gost/notifier" 13 "github.com/knqyf263/gost/util" 14 "github.com/spf13/cobra" 15 "github.com/spf13/viper" 16) 17 18// notifyCmd represents the notify command 19var notifyCmd = &cobra.Command{ 20 Use: "notify", 21 Short: "Notifiy update about the specified CVE", 22 Long: `Notifiy update about the specified CVE`, 23 RunE: executeNotify, 24} 25 26func init() { 27 RootCmd.AddCommand(notifyCmd) 28 29 RootCmd.PersistentFlags().Bool("to-email", false, "Send notification via Email") 30 viper.BindPFlag("to-email", RootCmd.PersistentFlags().Lookup("to-email")) 31 viper.SetDefault("to-email", false) 32 33 RootCmd.PersistentFlags().Bool("to-slack", false, "Send notification via Slack") 34 viper.BindPFlag("to-slack", RootCmd.PersistentFlags().Lookup("to-slack")) 35 viper.SetDefault("to-slack", false) 36} 37 38func executeNotify(cmd *cobra.Command, args []string) (err error) { 39 log15.Info("Load toml config") 40 var conf config.Config 41 if _, err = toml.DecodeFile("config.toml", &conf); err != nil { 42 return err 43 } 44 notifyRedhat(conf) 45 return err 46} 47 48func notifyRedhat(conf config.Config) error { 49 var watchCveURL []string 50 for cveID := range conf.Redhat { 51 watchCveURL = append(watchCveURL, fetcher.GetRedhatCveDetailURL(cveID)) 52 } 53 54 log15.Info(fmt.Sprintf("Fetched %d CVEs", len(watchCveURL))) 55 cveJSONs, err := fetcher.RetrieveRedhatCveDetails(watchCveURL) 56 if err != nil { 57 return err 58 } 59 60 cves, err := db.ConvertRedhat(cveJSONs) 61 if err != nil { 62 return nil 63 64 } 65 66 log15.Info("Initialize Database") 67 driver, locked, err := db.NewDB(viper.GetString("dbtype"), viper.GetString("dbpath"), viper.GetBool("debug-sql")) 68 if err != nil { 69 if locked { 70 log15.Error("Failed to initialize DB. Close DB connection before fetching", "err", err) 71 } 72 return err 73 } 74 75 for _, cve := range cves { 76 // Select CVE information from DB 77 c := driver.GetRedhat(cve.Name) 78 db.ClearIDRedhat(c) 79 80 cve.Cvss3.Cvss3BaseScore = "10 (This is dummy)" 81 cve.ThreatSeverity = "High (This is dummy)" 82 body := util.DiffRedhat(c, &cve, conf.Redhat[cve.Name]) 83 if body != "" { 84 subject := fmt.Sprintf("%s Update %s", conf.EMail.SubjectPrefix, cve.Name) 85 body = fmt.Sprintf("%s\nhttps://access.redhat.com/security/cve/%s\n========================================================\n", 86 cve.Name, cve.Name) + body 87 notify(subject, body, conf) 88 } 89 } 90 return nil 91} 92 93func notify(subject, body string, conf config.Config) (err error) { 94 if viper.GetBool("to-email") { 95 sender := notifier.NewEMailSender(conf.EMail) 96 log15.Info("Send e-mail") 97 if err = sender.Send(subject, body); err != nil { 98 return fmt.Errorf("Failed to send e-mail. err: %s", err) 99 } 100 } 101 102 if viper.GetBool("to-slack") { 103 log15.Info("Send slack") 104 if err = notifier.SendSlack(body, conf.Slack); err != nil { 105 return fmt.Errorf("Failed to send to Slack. err: %s", err) 106 } 107 } 108 return nil 109} 110