Skip to content

Commit 51dae53

Browse files
committed
Merge branch 'develop' of github.com:semaphoreui/semaphore into develop
2 parents fb63231 + 2d024cc commit 51dae53

File tree

5 files changed

+128
-20
lines changed

5 files changed

+128
-20
lines changed

pkg/task_logger/task_logger.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package task_logger
22

33
import (
44
"os/exec"
5-
"strings"
65
"time"
76
)
87

@@ -53,9 +52,11 @@ func (s TaskStatus) Format() (res string) {
5352
res += "⏹️"
5453
case TaskWaitingConfirmation:
5554
res += "⚠️"
55+
default:
56+
res += "❓"
5657
}
57-
res += strings.ToUpper(string(s))
58-
58+
// to avoid email content injection issue
59+
//res += strings.ToUpper(string(s))
5960
return
6061
}
6162

services/tasks/alert.go

+1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ func (t *TaskRunner) sendMailAlert() {
9292

9393
if err := mailer.Send(
9494
util.Config.EmailSecure,
95+
util.Config.EmailTls,
9596
util.Config.EmailHost,
9697
util.Config.EmailPort,
9798
util.Config.EmailUsername,

util/config.go

+9-7
Original file line numberDiff line numberDiff line change
@@ -198,13 +198,15 @@ type ConfigType struct {
198198
AccessKeyEncryption string `json:"access_key_encryption,omitempty" env:"SEMAPHORE_ACCESS_KEY_ENCRYPTION"`
199199

200200
// email alerting
201-
EmailAlert bool `json:"email_alert,omitempty" env:"SEMAPHORE_EMAIL_ALERT"`
202-
EmailSender string `json:"email_sender,omitempty" env:"SEMAPHORE_EMAIL_SENDER"`
203-
EmailHost string `json:"email_host,omitempty" env:"SEMAPHORE_EMAIL_HOST"`
204-
EmailPort string `json:"email_port,omitempty" rule:"^(|[0-9]{1,5})$" env:"SEMAPHORE_EMAIL_PORT"`
205-
EmailUsername string `json:"email_username,omitempty" env:"SEMAPHORE_EMAIL_USERNAME"`
206-
EmailPassword string `json:"email_password,omitempty" env:"SEMAPHORE_EMAIL_PASSWORD"`
207-
EmailSecure bool `json:"email_secure,omitempty" env:"SEMAPHORE_EMAIL_SECURE"`
201+
EmailAlert bool `json:"email_alert,omitempty" env:"SEMAPHORE_EMAIL_ALERT"`
202+
EmailSender string `json:"email_sender,omitempty" env:"SEMAPHORE_EMAIL_SENDER"`
203+
EmailHost string `json:"email_host,omitempty" env:"SEMAPHORE_EMAIL_HOST"`
204+
EmailPort string `json:"email_port,omitempty" rule:"^(|[0-9]{1,5})$" env:"SEMAPHORE_EMAIL_PORT"`
205+
EmailUsername string `json:"email_username,omitempty" env:"SEMAPHORE_EMAIL_USERNAME"`
206+
EmailPassword string `json:"email_password,omitempty" env:"SEMAPHORE_EMAIL_PASSWORD"`
207+
EmailSecure bool `json:"email_secure,omitempty" env:"SEMAPHORE_EMAIL_SECURE"`
208+
EmailTls bool `json:"email_tls,omitempty" env:"SEMAPHORE_EMAIL_TLS"`
209+
EmailTlsMinVersion string `json:"email_tls_min_version,omitempty" default:"1.2" rule:"^(1\\.[0123])$" env:"SEMAPHORE_EMAIL_TLS_MIN_VERSION"`
208210

209211
// ldap settings
210212
LdapEnable bool `json:"ldap_enable,omitempty" env:"SEMAPHORE_LDAP_ENABLE"`

util/config_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ func TestValidateConfig(t *testing.T) {
388388
var testDbDialect = DbDriverBolt
389389
var testCookieHash = "0Sn+edH3doJ4EO4Rl49Y0KrxjUkXuVtR5zKHGGWerxQ="
390390
var testMaxParallelTasks = 0
391+
var testEmailTlsMinVersion = "1.2"
391392

392393
Config.Port = testPort
393394
Config.Dialect = testDbDialect
@@ -396,6 +397,7 @@ func TestValidateConfig(t *testing.T) {
396397
Config.GitClientId = GoGitClientId
397398
Config.CookieEncryption = testCookieHash
398399
Config.AccessKeyEncryption = testCookieHash
400+
Config.EmailTlsMinVersion = testEmailTlsMinVersion
399401
validateConfig()
400402

401403
Config.Port = "INVALID"

util/mailer/mailer.go

+112-10
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@ package mailer
22

33
import (
44
"bytes"
5-
"html/template"
5+
"crypto/tls"
6+
"errors"
7+
"fmt"
8+
"github.com/semaphoreui/semaphore/util"
69
"net"
710
"net/smtp"
811
"strings"
12+
"text/template"
913
"time"
1014
)
1115

@@ -30,9 +34,25 @@ var (
3034
)
3135
)
3236

37+
func parseTlsVersion(version string) (uint16, error) {
38+
switch version {
39+
case "1.0":
40+
return tls.VersionTLS10, nil
41+
case "1.1":
42+
return tls.VersionTLS11, nil
43+
case "1.2":
44+
return tls.VersionTLS12, nil
45+
case "1.3":
46+
return tls.VersionTLS13, nil
47+
}
48+
49+
return 0, errors.New(fmt.Sprintf("Unsupported TLS version %s", version))
50+
}
51+
3352
// Send simply sends the defined mail via SMTP.
3453
func Send(
3554
secure bool,
55+
useTls bool,
3656
host string,
3757
port string,
3858
username,
@@ -68,15 +88,27 @@ func Send(
6888
}
6989

7090
if secure {
71-
return plainauth(
72-
host,
73-
port,
74-
username,
75-
password,
76-
from,
77-
to,
78-
body,
79-
)
91+
if useTls {
92+
return sendTls(
93+
host,
94+
port,
95+
username,
96+
password,
97+
from,
98+
to,
99+
body,
100+
)
101+
} else {
102+
return plainauth(
103+
host,
104+
port,
105+
username,
106+
password,
107+
from,
108+
to,
109+
body,
110+
)
111+
}
80112
}
81113

82114
return anonymous(
@@ -109,6 +141,76 @@ func plainauth(
109141
)
110142
}
111143

144+
func sendTls(
145+
host,
146+
port,
147+
username,
148+
password,
149+
from,
150+
to string,
151+
body *bytes.Buffer,
152+
) error {
153+
auth := PlainOrLoginAuth(username, password, host)
154+
155+
tlsVersion, err := parseTlsVersion(util.Config.EmailTlsMinVersion)
156+
if err != nil {
157+
return err
158+
}
159+
160+
tlsConfig := &tls.Config{
161+
InsecureSkipVerify: false,
162+
ServerName: host,
163+
MinVersion: tlsVersion,
164+
}
165+
166+
// Here is the key, you need to call tls.Dial instead of smtp.Dial
167+
// for smtp servers running on 465 that require an ssl connection
168+
// from the very beginning (no starttls)
169+
conn, err := tls.Dial("tcp", net.JoinHostPort(host, port), tlsConfig)
170+
if err != nil {
171+
return err
172+
}
173+
174+
c, err := smtp.NewClient(conn, host)
175+
if err != nil {
176+
return err
177+
}
178+
179+
if err = c.Auth(auth); err != nil {
180+
return err
181+
}
182+
183+
if err = c.Mail(from); err != nil {
184+
return err
185+
}
186+
187+
if err = c.Rcpt(to); err != nil {
188+
return err
189+
}
190+
191+
w, err := c.Data()
192+
if err != nil {
193+
return err
194+
}
195+
196+
_, err = w.Write(body.Bytes())
197+
if err != nil {
198+
return err
199+
}
200+
201+
err = w.Close()
202+
if err != nil {
203+
return err
204+
}
205+
206+
err = c.Quit()
207+
if err != nil {
208+
return err
209+
}
210+
211+
return nil
212+
}
213+
112214
func anonymous(
113215
host string,
114216
port string,

0 commit comments

Comments
 (0)