Stride support (#624)
This commit is contained in:
		@@ -57,6 +57,7 @@ type ReportCmd struct {
 | 
			
		||||
	ovalDBURL  string
 | 
			
		||||
 | 
			
		||||
	toSlack     bool
 | 
			
		||||
	toStride    bool
 | 
			
		||||
	toHipChat   bool
 | 
			
		||||
	toEMail     bool
 | 
			
		||||
	toSyslog    bool
 | 
			
		||||
@@ -114,6 +115,7 @@ func (*ReportCmd) Usage() string {
 | 
			
		||||
		[-ignore-unfixed]
 | 
			
		||||
		[-to-email]
 | 
			
		||||
		[-to-slack]
 | 
			
		||||
		[-to-stride]
 | 
			
		||||
		[-to-hipchat]
 | 
			
		||||
		[-to-localfile]
 | 
			
		||||
		[-to-s3]
 | 
			
		||||
@@ -265,6 +267,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")
 | 
			
		||||
	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.toEMail, "to-email", false, "Send report via Email")
 | 
			
		||||
	f.BoolVar(&p.toSyslog, "to-syslog", false, "Send report via Syslog")
 | 
			
		||||
@@ -331,6 +334,7 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
 | 
			
		||||
	c.Conf.HTTPProxy = p.httpProxy
 | 
			
		||||
 | 
			
		||||
	c.Conf.ToSlack = p.toSlack
 | 
			
		||||
	c.Conf.ToStride = p.toStride
 | 
			
		||||
	c.Conf.ToHipChat = p.toHipChat
 | 
			
		||||
	c.Conf.ToEmail = p.toEMail
 | 
			
		||||
	c.Conf.ToSyslog = p.toSyslog
 | 
			
		||||
@@ -370,6 +374,10 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
 | 
			
		||||
		reports = append(reports, report.SlackWriter{})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if p.toStride {
 | 
			
		||||
		reports = append(reports, report.StrideWriter{})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if p.toHipChat {
 | 
			
		||||
		reports = append(reports, report.HipChatWriter{})
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -96,6 +96,7 @@ type Config struct {
 | 
			
		||||
 | 
			
		||||
	EMail   SMTPConf
 | 
			
		||||
	Slack   SlackConf
 | 
			
		||||
	Stride  StrideConf
 | 
			
		||||
	HipChat HipChatConf
 | 
			
		||||
	Syslog  SyslogConf
 | 
			
		||||
	Default ServerInfo
 | 
			
		||||
@@ -129,6 +130,7 @@ type Config struct {
 | 
			
		||||
	RefreshCve bool
 | 
			
		||||
 | 
			
		||||
	ToSlack     bool
 | 
			
		||||
	ToStride    bool
 | 
			
		||||
	ToHipChat   bool
 | 
			
		||||
	ToEmail     bool
 | 
			
		||||
	ToSyslog    bool
 | 
			
		||||
@@ -277,6 +279,10 @@ func (c Config) ValidateOnReport() bool {
 | 
			
		||||
		errs = append(errs, hipchaterrs...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if strideerrs := c.Stride.Validate(); 0 < len(strideerrs) {
 | 
			
		||||
		errs = append(errs, strideerrs...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if syslogerrs := c.Syslog.Validate(); 0 < len(syslogerrs) {
 | 
			
		||||
		errs = append(errs, syslogerrs...)
 | 
			
		||||
	}
 | 
			
		||||
@@ -416,6 +422,33 @@ func (c *SMTPConf) Validate() (errs []error) {
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StrideConf is stride config
 | 
			
		||||
type StrideConf struct {
 | 
			
		||||
	HookURL   string `json:"hook_url"`
 | 
			
		||||
	AuthToken string `json:"AuthToken"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Validate validates configuration
 | 
			
		||||
func (c *StrideConf) Validate() (errs []error) {
 | 
			
		||||
	if !Conf.ToStride {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(c.HookURL) == 0 {
 | 
			
		||||
		errs = append(errs, fmt.Errorf("stride.HookURL must not be empty"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(c.AuthToken) == 0 {
 | 
			
		||||
		errs = append(errs, fmt.Errorf("stride.AuthToken must not be empty"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err := valid.ValidateStruct(c)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		errs = append(errs, err)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SlackConf is slack config
 | 
			
		||||
type SlackConf struct {
 | 
			
		||||
	HookURL     string `valid:"url" json:"-"`
 | 
			
		||||
 
 | 
			
		||||
@@ -44,6 +44,7 @@ func (c TOMLLoader) Load(pathToToml, keyPass string) error {
 | 
			
		||||
 | 
			
		||||
	Conf.EMail = conf.EMail
 | 
			
		||||
	Conf.Slack = conf.Slack
 | 
			
		||||
	Conf.Stride = conf.Stride
 | 
			
		||||
	Conf.HipChat = conf.HipChat
 | 
			
		||||
	Conf.Syslog = conf.Syslog
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										75
									
								
								report/stride.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								report/stride.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,75 @@
 | 
			
		||||
package report
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"github.com/future-architect/vuls/config"
 | 
			
		||||
	"github.com/future-architect/vuls/models"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// StrideWriter send report to Stride
 | 
			
		||||
type StrideWriter struct{}
 | 
			
		||||
type StrideSender struct{}
 | 
			
		||||
 | 
			
		||||
func (w StrideWriter) Write(rs ...models.ScanResult) (err error) {
 | 
			
		||||
	conf := config.Conf.Stride
 | 
			
		||||
 | 
			
		||||
	for _, r := range rs {
 | 
			
		||||
		w := StrideSender{}
 | 
			
		||||
		jsonStr := `{"body":{"version":1,"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"` + r.ServerName + `"}]}]}}`
 | 
			
		||||
		err = w.sendMessage(conf.HookURL, conf.AuthToken, jsonStr)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for _, vinfo := range r.ScannedCves {
 | 
			
		||||
			maxCvss := vinfo.MaxCvssScore()
 | 
			
		||||
			severity := strings.ToUpper(maxCvss.Value.Severity)
 | 
			
		||||
			if severity == "" {
 | 
			
		||||
				severity = "?"
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			jsonStr = `{"body":{"version":1,"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"` + vinfo.CveID + `","marks": [ { "type": "link", "attrs": { "href": "https://nvd.nist.gov/vuln/detail/` + vinfo.CveID + `", "title": "cve" } } ]}]}]}}`
 | 
			
		||||
			w.sendMessage(conf.HookURL, conf.AuthToken, jsonStr)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			jsonStr = `{"body":{"version":1,"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"` + strconv.FormatFloat(maxCvss.Value.Score, 'f', 1, 64) + "(" + severity + ")" + `"}]}]}}`
 | 
			
		||||
			w.sendMessage(conf.HookURL, conf.AuthToken, jsonStr)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			jsonStr = `{"body":{"version":1,"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"` + vinfo.Summaries(config.Conf.Lang, r.Family)[0].Value + `"}]}]}}`
 | 
			
		||||
			w.sendMessage(conf.HookURL, conf.AuthToken, jsonStr)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w StrideSender) sendMessage(uri, token, jsonStr string) error {
 | 
			
		||||
 | 
			
		||||
	reqs, err := http.NewRequest("POST", uri, bytes.NewBuffer([]byte(jsonStr)))
 | 
			
		||||
 | 
			
		||||
	reqs.Header.Add("Content-Type", "application/json")
 | 
			
		||||
	reqs.Header.Add("Authorization", "Bearer "+token)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	client := &http.Client{}
 | 
			
		||||
 | 
			
		||||
	resp, err := client.Do(reqs)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer resp.Body.Close()
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								report/stride_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								report/stride_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
package report
 | 
			
		||||
		Reference in New Issue
	
	Block a user