Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
209 lines
5.0 KiB
Go
209 lines
5.0 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"fmt"
|
|
htpl "html/template"
|
|
"io/ioutil"
|
|
"strings"
|
|
|
|
intAuth "github.com/cortezaproject/corteza/server/pkg/auth"
|
|
"github.com/cortezaproject/corteza/server/pkg/mail"
|
|
"github.com/cortezaproject/corteza/server/pkg/options"
|
|
"github.com/cortezaproject/corteza/server/system/types"
|
|
gomail "gopkg.in/mail.v2"
|
|
)
|
|
|
|
type (
|
|
smtpConfigurationChecker struct {
|
|
settings *types.AppSettings
|
|
ts TemplateService
|
|
opt options.AuthOpt
|
|
accessControl smtpCheckAccessController
|
|
}
|
|
|
|
smtpCheckAccessController interface {
|
|
CanManageSettings(context.Context) bool
|
|
}
|
|
)
|
|
|
|
func SmtpConfigurationChecker(s *types.AppSettings, ts TemplateService, ac accessController, opt options.AuthOpt) *smtpConfigurationChecker {
|
|
return &smtpConfigurationChecker{
|
|
settings: s,
|
|
ts: ts,
|
|
opt: opt,
|
|
accessControl: ac,
|
|
}
|
|
}
|
|
|
|
// Check SMTP server configurations and send a test email
|
|
// to recipients if they're provided
|
|
func (svc smtpConfigurationChecker) Check(ctx context.Context, smtpConfigs *types.SmtpConfiguration) (checkResults *types.SmtpCheckResult, err error) {
|
|
if !svc.accessControl.CanManageSettings(ctx) {
|
|
return nil, fmt.Errorf("not allowed to check SMTP configurations")
|
|
}
|
|
|
|
var (
|
|
tlsConfig = &tls.Config{}
|
|
)
|
|
|
|
checkResults = &types.SmtpCheckResult{}
|
|
|
|
if smtpConfigs.Port == 0 {
|
|
smtpConfigs.Port = 25
|
|
}
|
|
|
|
//check for validity of the host
|
|
if !mail.IsValidHost(smtpConfigs.Host) {
|
|
checkResults.Host = fmt.Sprintf("%s name is Invalid", smtpConfigs.Host)
|
|
}
|
|
|
|
// Applying TLS
|
|
tlsConfig = &tls.Config{ServerName: smtpConfigs.Host}
|
|
|
|
if smtpConfigs.TLSInsecure {
|
|
tlsConfig.InsecureSkipVerify = true
|
|
}
|
|
|
|
if smtpConfigs.TLSServerName != "" {
|
|
tlsConfig.ServerName = smtpConfigs.TLSServerName
|
|
}
|
|
|
|
checkResults.Server = mail.ConfigCheck(smtpConfigs.Host, smtpConfigs.Port, smtpConfigs.Username, smtpConfigs.Password, tlsConfig)
|
|
|
|
//send the email there are recipients
|
|
if checkResults.Server == "" {
|
|
if len(smtpConfigs.Recipients) != 0 {
|
|
checkResults.Send, err = svc.smtpSend(ctx, smtpConfigs.Recipients)
|
|
}
|
|
}
|
|
|
|
return checkResults, err
|
|
}
|
|
|
|
func (svc smtpConfigurationChecker) smtpSend(ctx context.Context, recipients []string) (expected string, err error) {
|
|
var (
|
|
ntf = mail.New()
|
|
toHeader string
|
|
// context with service user
|
|
// we need this for retrieving & rendering email templates
|
|
suCtx = intAuth.SetIdentityToContext(ctx, intAuth.ServiceUser())
|
|
)
|
|
|
|
if err = svc.procEmailRecipients(ntf, "To", recipients); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
toHeader = strings.Join(recipients, ",")
|
|
ntf.SetAddressHeader("To", toHeader, "")
|
|
|
|
st, ct, err := svc.findEmailTemplates(suCtx)
|
|
// if we cannot find an email template
|
|
if err != nil {
|
|
ntf.SetHeader("Subject", "SMTP Configuration check")
|
|
ntf.SetBody("text/html", "<h2 style=\"color: #FF9661;text-align: center;\">SMTP configurations check passed</h2>")
|
|
|
|
err = mail.Send(ntf)
|
|
|
|
if err != nil {
|
|
return err.Error(), nil
|
|
}
|
|
|
|
return "", nil
|
|
}
|
|
|
|
subjectTmp, contentTmp, err := svc.procEmailTemplate(suCtx, st.ID, ct.ID)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
ntf.SetHeader("Subject", string(subjectTmp))
|
|
ntf.SetBody("text/html", string(contentTmp))
|
|
|
|
err = mail.Send(ntf)
|
|
|
|
if err != nil {
|
|
return err.Error(), nil
|
|
}
|
|
|
|
return "", nil
|
|
}
|
|
|
|
func (svc smtpConfigurationChecker) procEmailRecipients(m *gomail.Message, field string, recipients []string) (err error) {
|
|
var (
|
|
email string
|
|
rcpt string
|
|
)
|
|
|
|
if len(recipients) == 0 {
|
|
return
|
|
}
|
|
|
|
for _, rcpt = range recipients {
|
|
|
|
email = strings.TrimSpace(rcpt)
|
|
|
|
// Validate email here
|
|
if !mail.IsValidAddress(email) {
|
|
return fmt.Errorf("invalid recipient email address %s", email)
|
|
}
|
|
|
|
}
|
|
|
|
m.SetHeader(field, recipients...)
|
|
return nil
|
|
}
|
|
|
|
// procEmailTemplate processes Email address template based on the template's subject ID and content ID
|
|
func (svc smtpConfigurationChecker) procEmailTemplate(ctx context.Context, stId uint64, ctId uint64) (subjectTmp []byte, contentTmp []byte, err error) {
|
|
// Prepare payload
|
|
payload := map[string]interface{}{
|
|
"Logo": htpl.URL(svc.settings.General.Mail.Logo),
|
|
"BaseURL": svc.opt.BaseURL,
|
|
}
|
|
|
|
// Render document
|
|
subject, err := svc.ts.Render(ctx, stId, "text/plain", payload, nil, types.TemplateRenderAux{})
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
content, err := svc.ts.Render(ctx, ctId, "text/plain", payload, nil, types.TemplateRenderAux{})
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
subjectTmp, err = ioutil.ReadAll(subject)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
contentTmp, err = ioutil.ReadAll(content)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return subjectTmp, contentTmp, nil
|
|
}
|
|
|
|
func (svc smtpConfigurationChecker) findEmailTemplates(ctx context.Context) (st *types.Template, ct *types.Template, err error) {
|
|
var (
|
|
hdl string
|
|
)
|
|
|
|
hdl = "smtp_configuration_check_subject"
|
|
st, err = svc.ts.FindByHandle(ctx, hdl)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
hdl = "smtp_configuration_check_content"
|
|
ct, err = svc.ts.FindByHandle(ctx, hdl)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return st, ct, nil
|
|
}
|