Passed
Pull Request — master (#771)
by
unknown
05:17
created

report.*emailSender.Send   C

Complexity

Conditions 8

Size

Total Lines 54
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 43
dl 0
loc 54
rs 6.9813
c 0
b 0
f 0
nop 2

How to fix   Long Method   

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:

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
45
			mm := r.ScannedCves.CountGroupBySeverity()
46
			keys := []string{"High", "Medium", "Low", "Unknown"}
47
			for _, k := range keys {
48
				m[k] += mm[k]
49
			}
50
		} else {
51
			var subject string
52
			if len(r.Errors) != 0 {
53
				subject = fmt.Sprintf("%s%s An error occurred while scanning",
54
					conf.EMail.SubjectPrefix, r.ServerInfo())
55
			} else {
56
				subject = fmt.Sprintf("%s%s %s",
57
					conf.EMail.SubjectPrefix,
58
					r.ServerInfo(),
59
					r.ScannedCves.FormatCveSummary())
60
			}
61
			if conf.FormatList {
62
				message = formatList(r)
63
			} else {
64
				message = formatFullPlainText(r)
65
			}
66
			if err := sender.Send(subject, message); err != nil {
67
				return err
68
			}
69
		}
70
	}
71
72
	summary := ""
73
	if config.Conf.IgnoreUnscoredCves {
74
		summary = fmt.Sprintf("Total: %d (High:%d Medium:%d Low:%d)",
75
			m["High"]+m["Medium"]+m["Low"], m["High"], m["Medium"], m["Low"])
76
	}
77
	summary = fmt.Sprintf("Total: %d (High:%d Medium:%d Low:%d ?:%d)",
78
		m["High"]+m["Medium"]+m["Low"]+m["Unknown"],
79
		m["High"], m["Medium"], m["Low"], m["Unknown"])
80
81
	if conf.FormatOneEMail {
82
		message = fmt.Sprintf(
83
			`
84
One Line Summary
85
================
86
%s
87
88
89
%s`,
90
			formatOneLineSummary(rs...), message)
91
92
		subject := fmt.Sprintf("%s %s",
93
			conf.EMail.SubjectPrefix, summary)
94
		return sender.Send(subject, message)
95
	}
96
	return nil
97
}
98
99
// EMailSender is interface of sending e-mail
100
type EMailSender interface {
101
	Send(subject, body string) error
102
}
103
104
type emailSender struct {
105
	conf config.SMTPConf
106
	send func(string, smtp.Auth, string, []string, []byte) error
107
}
108
109
func (e *emailSender) Send(subject, body string) (err error) {
110
	emailConf := e.conf
111
	to := strings.Join(emailConf.To[:], ", ")
112
	cc := strings.Join(emailConf.Cc[:], ", ")
113
	mailAddresses := append(emailConf.To, emailConf.Cc...)
114
	if _, err := mail.ParseAddressList(strings.Join(mailAddresses[:], ", ")); err != nil {
115
		return fmt.Errorf("Failed to parse email addresses: %s", err)
116
	}
117
118
	headers := make(map[string]string)
119
	headers["From"] = emailConf.From
120
	headers["To"] = to
121
	headers["Cc"] = cc
122
	headers["Subject"] = subject
123
	headers["Date"] = time.Now().Format(time.RFC1123Z)
124
	headers["Content-Type"] = "text/plain; charset=utf-8"
125
126
	var header string
127
	for k, v := range headers {
128
		header += fmt.Sprintf("%s: %s\r\n", k, v)
129
	}
130
	message := fmt.Sprintf("%s\r\n%s", header, body)
131
132
	smtpServer := net.JoinHostPort(emailConf.SMTPAddr, emailConf.SMTPPort)
133
134
	if emailConf.User != "" && emailConf.Password != "" {
135
		err = e.send(
136
			smtpServer,
137
			smtp.PlainAuth(
138
				"",
139
				emailConf.User,
140
				emailConf.Password,
141
				emailConf.SMTPAddr,
142
			),
143
			emailConf.From,
144
			mailAddresses,
145
			[]byte(message),
146
		)
147
		if err != nil {
148
			return fmt.Errorf("Failed to send emails: %s", err)
149
		}
150
		return nil
151
	} else {
0 ignored issues
show
introduced by
if block ends with a return statement, so drop this else and outdent its block
Loading history...
152
		err = e.send(
153
			smtpServer,
154
			nil,
155
			emailConf.From,
156
			mailAddresses,
157
			[]byte(message),
158
		)
159
		if err != nil {
160
			return fmt.Errorf("Failed to send emails: %s", err)
161
		}
162
		return nil
163
	}
164
}
165
166
// NewEMailSender creates emailSender
167
func NewEMailSender() EMailSender {
168
	return &emailSender{config.Conf.EMail, smtp.SendMail}
169
}
170