Skip to content

Instantly share code, notes, and snippets.

@oshiro-kazuma
Last active April 13, 2018 10:52
Show Gist options
  • Save oshiro-kazuma/6f0441a493f0d60bb9d02da84afd23b1 to your computer and use it in GitHub Desktop.
Save oshiro-kazuma/6f0441a493f0d60bb9d02da84afd23b1 to your computer and use it in GitHub Desktop.
hipchat support #593
config/config.go
@@ -96,6 +96,7 @@ type Config struct {
EMail SMTPConf
Slack SlackConf
// config追加
+ HipChat HipChatConf
Syslog SyslogConf
Default ServerInfo
Servers map[string]ServerInfo
@@ -263,6 +264,10 @@ func (c Config) ValidateOnReport() bool {
errs = append(errs, slackerrs...)
}
// 確かconfig validate的なコマンドがあって、hipchatのconfig validateも呼ぶように追加
// そんなコマンドはないかも。ただ-to-hipchatオプションを付けたのにhipchatの設定がない場合
// エラーが出ると思うので、そのへんの処理。
+ if hipchaterrs := c.HipChat.Validate(); 0 < len(hipchaterrs) {
+ errs = append(errs, hipchaterrs...)
+ }
+
if syslogerrs := c.Syslog.Validate(); 0 < len(syslogerrs) {
errs = append(errs, syslogerrs...)
}
@@ -451,6 +456,30 @@ func (c *SlackConf) Validate() (errs []error) {
return
}
// tomlのhip chat configを受け取る構造体
+// HipChatConf is HipChat config
+type HipChatConf struct {
+ AuthToken string `json:"AuthToken"`
+ Room string `json:"Room"`
+}
+
// configのvalidate処理
+// Validate validates configuration
+func (c *HipChatConf) Validate() (errs []error) {
+ if len(c.Room) == 0 {
+ errs = append(errs, fmt.Errorf("room must not be empty"))
+ }
+
+ if len(c.AuthToken) == 0 {
+ errs = append(errs, fmt.Errorf("AuthToken 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
// HipChatWriterの定義。Writeメソッドを定義して、vuls report -to-hipchatを実行されたとき、標準出力に加えてhipchatにもoutputする的なやつ。
// ChatWorkWriterを作って、WriteでChatwork APIを呼べばおk
@@ -0,0 +1,70 @@
+package report
+
+import (
+ "fmt"
+ "net/http"
+ "net/url"
+ "strconv"
+ "strings"
+
+ "github.com/future-architect/vuls/config"
+ "github.com/future-architect/vuls/models"
+)
+
+// HipChatWriter send report to HipChat
+type HipChatWriter struct{}
+
+func (w HipChatWriter) Write(rs ...models.ScanResult) (err error) {
// tomlをパースしてconfig.Conf.HipChatに設定値が入るので取得。
+ conf := config.Conf.HipChat
+
+ var message string
+ for _, r := range rs {
// api call.まずはサーバー名を投稿しているっぽい。
+ err = postMessage(conf.Room, conf.AuthToken, r.ServerName)
+ if err != nil {
+ return err
+ }
+
// メッセージ組み立て処理、CVEの値をループ
+ for _, vinfo := range r.ScannedCves {
+ maxCvss := vinfo.MaxCvssScore()
+ severity := strings.ToUpper(maxCvss.Value.Severity)
+ if severity == "" {
+ severity = "?"
+ }
+
// メッセージ生成
+ message = `<a href="https://nvd.nist.gov/vuln/detail\">` + vinfo.CveID + "</a>" + "<br/>" + strconv.FormatFloat(maxCvss.Value.Score, 'f', 1, 64) + " " + "(" + severity + ")" + "<br/>" + vinfo.Summaries(config.Conf.Lang, r.Family)[0].Value
+
// hipchat api call
+ err = postMessage(conf.Room, conf.AuthToken, message)
+ if err != nil {
+ return err
+ }
+ }
+
+ }
+ return nil
+}
+
+func postMessage(room, token, message string) error {
// hip chat api url生成、token埋め込み
+ uri := fmt.Sprintf("https://api.hipchat.com/v2/room/%s/notification?auth_token=%s", room, token)
+
// payload生成
+ payload := url.Values{
+ "color": {"purple"},
+ "message_format": {"html"},
+ "message": {message},
+ }
// hip chatにpayloadを添えてPOST
+ reqs, err := http.NewRequest("POST", uri, strings.NewReader(payload.Encode()))
+
+ reqs.Header.Add("Content-Type", "application/x-www-form-urlencoded")
+
+ if err != nil {
+ return err
+ }
+ client := &http.Client{}
+
// ここでHTTP Requestをなげる
+ resp, err := client.Do(reqs)
+ if err != nil {
+ return err
+ }
// もうメソッド終わるのでdefer つけなくていいけどhttp body readerをclose
// deferをメソッドの頭につけると、この関数を抜ける(return)するときに必ず呼び出されるようになる。
// もう直後でreturnしているのでdeferなくても良い。慣習的にやっているだけ。
+ defer resp.Body.Close()
+
+ return nil
+}
//https://github.com/future-architect/vuls/pull/593/files
7 commands/report.go
@@ -57,6 +57,7 @@ type ReportCmd struct {
ovalDBURL string
toSlack bool
// toHipChatオプションの変数追加
+ toHipChat bool
toEMail bool
toSyslog bool
toLocalFile bool
@@ -114,6 +115,7 @@ func (*ReportCmd) Usage() string {
[-ignore-unfixed]
[-to-email]
[-to-slack]
// vuls report --helpやvuls report --helpを実行したときに表示されるusageに-to-hipchatオプションがある旨を追記している
+ [-to-hipchat]
[-to-localfile]
[-to-s3]
[-to-azure-blob]
@@ -264,6 +266,7 @@ func (p *ReportCmd) SetFlags(f *flag.FlagSet) {
f.BoolVar(&p.gzip, "gzip", false, "gzip compression")
f.BoolVar(&p.toSlack, "to-slack", false, "Send report via Slack")
// コマンドラインオプションを受け取って、初めの方で定義した to-hipchat にbooleanの値を入れている
+ f.BoolVar(&p.toHipChat, "to-hipchat", false, "Send report via hipchat")
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,
@@ -361,6 +364,10 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
reports = append(reports, report.SlackWriter{})
}
// toHipChatがtureだったらreport.HipChatWriterをreportsに入れる的な。
// reportsの型は[]report.ResultWriterで、多分どっかでreportsのループ回してそれぞれの変数に対して.Write()を実行している
// ReportWriterはWrite(.../models.ScanResut)のメソッドを実装していないといけない。
//
//
// type ResultWriter interface {
// Write(...models.ScanResult) error
// }
//
// chatworkに通知を飛ばしたいのであれば、ChatWorkWriter構造体を作って、Writeメソッドを生やしてここに追加すればおk
+ if p.toHipChat {
+ reports = append(reports, report.HipChatWriter{})
+ }
+
if p.toEMail {
reports = append(reports, report.EMailWriter{})
}
@@ -44,6 +44,7 @@ func (c TOMLLoader) Load(pathToToml, keyPass string) error {
Conf.EMail = conf.EMail
Conf.Slack = conf.Slack
// tomlってる
+ Conf.HipChat = conf.HipChat
Conf.Syslog = conf.Syslog
d := conf.Default
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment