Completed
Push — master ( cf6fb0...5c6e06 )
by kota
05:52
created

report.EMailWriter.Write   D

Complexity

Conditions 13

Size

Total Lines 58
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 46
dl 0
loc 58
rs 4.2
c 0
b 0
f 0
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like report.EMailWriter.Write often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/* Vuls - Vulnerability Scanner
2
Copyright (C) 2016  Future Corporation , Japan.
3
4
This program is free software: you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation, either version 3 of the License, or
7
(at your option) any later version.
8
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
GNU General Public License for more details.
13
14
You should have received a copy of the GNU General Public License
15
along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
*/
17
18
package report
19
20
import (
21
	"fmt"
22
	"net"
23
	"net/mail"
24
	"net/smtp"
25
	"strings"
26
	"time"
27
28
	"github.com/future-architect/vuls/config"
29
	"github.com/future-architect/vuls/models"
30
)
31
32
// EMailWriter send mail
33
type EMailWriter struct{}
34
35
func (w EMailWriter) Write(rs ...models.ScanResult) (err error) {
36
	conf := config.Conf
37
	var message string
38
	sender := NewEMailSender()
39
40
	m := map[string]int{}
41
	for _, r := range rs {
42
		if conf.FormatOneEMail {
43
			message += formatFullPlainText(r) + "\r\n\r\n"
44
			mm := r.ScannedCves.CountGroupBySeverity()
45
			keys := []string{"High", "Medium", "Low", "Unknown"}
46
			for _, k := range keys {
47
				m[k] += mm[k]
48
			}
49
		} else {
50
			var subject string
51
			if len(r.Errors) != 0 {
52
				subject = fmt.Sprintf("%s%s An error occurred while scanning",
53
					conf.EMail.SubjectPrefix, r.ServerInfo())
54
			} else {
55
				subject = fmt.Sprintf("%s%s %s",
56
					conf.EMail.SubjectPrefix,
57
					r.ServerInfo(),
58
					r.ScannedCves.FormatCveSummary())
59
			}
60
			if conf.FormatList {
61
				message = formatList(r)
62
			} else {
63
				message = formatFullPlainText(r)
64
			}
65
			if conf.FormatOneLineText {
66
				message = fmt.Sprintf("One Line Summary\r\n================\r\n%s", formatOneLineSummary(r))
67
			}
68
			if err := sender.Send(subject, message); err != nil {
69
				return err
70
			}
71
		}
72
	}
73
	summary := ""
74
	if config.Conf.IgnoreUnscoredCves {
75
		summary = fmt.Sprintf("Total: %d (High:%d Medium:%d Low:%d)",
76
			m["High"]+m["Medium"]+m["Low"], m["High"], m["Medium"], m["Low"])
77
	}
78
	summary = fmt.Sprintf("Total: %d (High:%d Medium:%d Low:%d ?:%d)",
79
		m["High"]+m["Medium"]+m["Low"]+m["Unknown"],
80
		m["High"], m["Medium"], m["Low"], m["Unknown"])
81
	origmessage := message
82
	if conf.FormatOneEMail {
83
		message = fmt.Sprintf("One Line Summary\r\n================\r\n%s", formatOneLineSummary(rs...))
84
		if !conf.FormatOneLineText {
85
			message += fmt.Sprintf("\r\n\r\n%s", origmessage)
86
		}
87
88
		subject := fmt.Sprintf("%s %s",
89
			conf.EMail.SubjectPrefix, summary)
90
		return sender.Send(subject, message)
91
	}
92
	return nil
93
}
94
95
// EMailSender is interface of sending e-mail
96
type EMailSender interface {
97
	Send(subject, body string) error
98
}
99
100
type emailSender struct {
101
	conf config.SMTPConf
102
	send func(string, smtp.Auth, string, []string, []byte) error
103
}
104
105
func (e *emailSender) Send(subject, body string) (err error) {
106
	emailConf := e.conf
107
	to := strings.Join(emailConf.To[:], ", ")
108
	cc := strings.Join(emailConf.Cc[:], ", ")
109
	mailAddresses := append(emailConf.To, emailConf.Cc...)
110
	if _, err := mail.ParseAddressList(strings.Join(mailAddresses[:], ", ")); err != nil {
111
		return fmt.Errorf("Failed to parse email addresses: %s", err)
112
	}
113
114
	headers := make(map[string]string)
115
	headers["From"] = emailConf.From
116
	headers["To"] = to
117
	headers["Cc"] = cc
118
	headers["Subject"] = subject
119
	headers["Date"] = time.Now().Format(time.RFC1123Z)
120
	headers["Content-Type"] = "text/plain; charset=utf-8"
121
122
	var header string
123
	for k, v := range headers {
124
		header += fmt.Sprintf("%s: %s\r\n", k, v)
125
	}
126
	message := fmt.Sprintf("%s\r\n%s", header, body)
127
128
	smtpServer := net.JoinHostPort(emailConf.SMTPAddr, emailConf.SMTPPort)
129
130
	if emailConf.User != "" && emailConf.Password != "" {
131
		err = e.send(
132
			smtpServer,
133
			smtp.PlainAuth(
134
				"",
135
				emailConf.User,
136
				emailConf.Password,
137
				emailConf.SMTPAddr,
138
			),
139
			emailConf.From,
140
			mailAddresses,
141
			[]byte(message),
142
		)
143
		if err != nil {
144
			return fmt.Errorf("Failed to send emails: %s", err)
145
		}
146
		return nil
147
	}
148
	err = e.send(
149
		smtpServer,
150
		nil,
151
		emailConf.From,
152
		mailAddresses,
153
		[]byte(message),
154
	)
155
	if err != nil {
156
		return fmt.Errorf("Failed to send emails: %s", err)
157
	}
158
	return nil
159
}
160
161
// NewEMailSender creates emailSender
162
func NewEMailSender() EMailSender {
163
	return &emailSender{config.Conf.EMail, smtp.SendMail}
164
}
165