From 314f77524372f5ee3aa21d79ba0d42a56cd9b23d Mon Sep 17 00:00:00 2001 From: adachin Date: Fri, 27 Apr 2018 14:59:58 +0900 Subject: [PATCH] Chatwork support (#634) --- commands/report.go | 8 +++++ config/config.go | 46 ++++++++++++++++++++++---- config/tomlloader.go | 1 + report/chatwork.go | 73 +++++++++++++++++++++++++++++++++++++++++ report/chatwork_test.go | 1 + 5 files changed, 122 insertions(+), 7 deletions(-) create mode 100644 report/chatwork.go create mode 100644 report/chatwork_test.go diff --git a/commands/report.go b/commands/report.go index 6398234e..5e23573a 100644 --- a/commands/report.go +++ b/commands/report.go @@ -59,6 +59,7 @@ type ReportCmd struct { toSlack bool toStride bool toHipChat bool + toChatWork bool toEMail bool toSyslog bool toLocalFile bool @@ -117,6 +118,7 @@ func (*ReportCmd) Usage() string { [-to-slack] [-to-stride] [-to-hipchat] + [-to-chatwork] [-to-localfile] [-to-s3] [-to-azure-blob] @@ -269,6 +271,7 @@ func (p *ReportCmd) SetFlags(f *flag.FlagSet) { f.BoolVar(&p.toSlack, "to-slack", false, "Send report via Slack") f.BoolVar(&p.toStride, "to-stride", false, "Send report via Stride") f.BoolVar(&p.toHipChat, "to-hipchat", false, "Send report via hipchat") + f.BoolVar(&p.toChatWork, "to-chatwork", false, "Send report via chatwork") f.BoolVar(&p.toEMail, "to-email", false, "Send report via Email") f.BoolVar(&p.toSyslog, "to-syslog", false, "Send report via Syslog") f.BoolVar(&p.toLocalFile, @@ -336,6 +339,7 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{} c.Conf.ToSlack = p.toSlack c.Conf.ToStride = p.toStride c.Conf.ToHipChat = p.toHipChat + c.Conf.ToChatWork = p.toChatWork c.Conf.ToEmail = p.toEMail c.Conf.ToSyslog = p.toSyslog c.Conf.ToLocalFile = p.toLocalFile @@ -382,6 +386,10 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{} reports = append(reports, report.HipChatWriter{}) } + if p.toChatWork { + reports = append(reports, report.ChatWorkWriter{}) + } + if p.toEMail { reports = append(reports, report.EMailWriter{}) } diff --git a/config/config.go b/config/config.go index ed16e84d..a96558c3 100644 --- a/config/config.go +++ b/config/config.go @@ -94,13 +94,14 @@ type Config struct { DebugSQL bool Lang string - EMail SMTPConf - Slack SlackConf - Stride StrideConf - HipChat HipChatConf - Syslog SyslogConf - Default ServerInfo - Servers map[string]ServerInfo + EMail SMTPConf + Slack SlackConf + Stride StrideConf + HipChat HipChatConf + ChatWork ChatWorkConf + Syslog SyslogConf + Default ServerInfo + Servers map[string]ServerInfo CvssScoreOver float64 IgnoreUnscoredCves bool @@ -132,6 +133,7 @@ type Config struct { ToSlack bool ToStride bool ToHipChat bool + ToChatWork bool ToEmail bool ToSyslog bool ToLocalFile bool @@ -279,6 +281,10 @@ func (c Config) ValidateOnReport() bool { errs = append(errs, hipchaterrs...) } + if chatworkerrs := c.ChatWork.Validate(); 0 < len(chatworkerrs) { + errs = append(errs, chatworkerrs...) + } + if strideerrs := c.Stride.Validate(); 0 < len(strideerrs) { errs = append(errs, strideerrs...) } @@ -519,6 +525,32 @@ func (c *HipChatConf) Validate() (errs []error) { return } +// ChatWorkConf is ChatWork config +type ChatWorkConf struct { + ApiToken string `json:"ApiToken"` + Room string `json:"Room"` +} + +// Validate validates configuration +func (c *ChatWorkConf) Validate() (errs []error) { + if !Conf.ToChatWork { + return + } + if len(c.Room) == 0 { + errs = append(errs, fmt.Errorf("chatworkcaht.room must not be empty")) + } + + if len(c.ApiToken) == 0 { + errs = append(errs, fmt.Errorf("chatworkcaht.ApiToken must not be empty")) + } + + _, err := valid.ValidateStruct(c) + if err != nil { + errs = append(errs, err) + } + return +} + // SyslogConf is syslog config type SyslogConf struct { Protocol string diff --git a/config/tomlloader.go b/config/tomlloader.go index 4bb9e043..92559379 100644 --- a/config/tomlloader.go +++ b/config/tomlloader.go @@ -46,6 +46,7 @@ func (c TOMLLoader) Load(pathToToml, keyPass string) error { Conf.Slack = conf.Slack Conf.Stride = conf.Stride Conf.HipChat = conf.HipChat + Conf.ChatWork = conf.ChatWork Conf.Syslog = conf.Syslog d := conf.Default diff --git a/report/chatwork.go b/report/chatwork.go new file mode 100644 index 00000000..3c1deef1 --- /dev/null +++ b/report/chatwork.go @@ -0,0 +1,73 @@ +package report + +import ( + "fmt" + "net/http" + "net/url" + "strconv" + "strings" + + "github.com/future-architect/vuls/config" + "github.com/future-architect/vuls/models" +) + +// ChatWorkWriter send report to ChatWork +type ChatWorkWriter struct{} + +func (w ChatWorkWriter) Write(rs ...models.ScanResult) (err error) { + conf := config.Conf.ChatWork + + for _, r := range rs { + serverInfo := fmt.Sprintf("%s", r.ServerInfo()) + if err = ChatWorkpostMessage(conf.Room, conf.ApiToken, serverInfo); err != nil { + return err + } + + for _, vinfo := range r.ScannedCves { + maxCvss := vinfo.MaxCvssScore() + severity := strings.ToUpper(maxCvss.Value.Severity) + if severity == "" { + severity = "?" + } + + message := fmt.Sprintf(`%s[info][title]"https://nvd.nist.gov/vuln/detail/%s" %s %s[/title]%s[/info]`, + serverInfo, + vinfo.CveID, + strconv.FormatFloat(maxCvss.Value.Score, 'f', 1, 64), + severity, + vinfo.Summaries(config.Conf.Lang, r.Family)[0].Value) + + if err = ChatWorkpostMessage(conf.Room, conf.ApiToken, message); err != nil { + return err + } + } + + } + return nil +} + +func ChatWorkpostMessage(room, token, message string) error { + uri := fmt.Sprintf("https://api.chatwork.com/v2/rooms/%s/messages=%s", room, token) + + payload := url.Values{ + "body": {message}, + } + + reqs, err := http.NewRequest("POST", uri, strings.NewReader(payload.Encode())) + + reqs.Header.Add("X-ChatWorkToken", token) + reqs.Header.Add("Content-Type", "application/x-www-form-urlencoded") + + if err != nil { + return err + } + client := &http.Client{} + + resp, err := client.Do(reqs) + if err != nil { + return err + } + defer resp.Body.Close() + + return nil +} diff --git a/report/chatwork_test.go b/report/chatwork_test.go new file mode 100644 index 00000000..80c499fb --- /dev/null +++ b/report/chatwork_test.go @@ -0,0 +1 @@ +package report