2020-04-17 17:53:01 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"io"
|
|
|
|
"log"
|
|
|
|
"os"
|
|
|
|
|
|
|
|
"forge.cadoles.com/wpetit/fake-smtp/internal/command"
|
|
|
|
"forge.cadoles.com/wpetit/fake-smtp/internal/config"
|
|
|
|
"github.com/emersion/go-smtp"
|
|
|
|
"github.com/jhillyerd/enmime"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"gitlab.com/wpetit/goweb/cqrs"
|
2020-11-05 19:48:18 +01:00
|
|
|
"gitlab.com/wpetit/goweb/logger"
|
2020-04-17 17:53:01 +02:00
|
|
|
"gitlab.com/wpetit/goweb/middleware/container"
|
|
|
|
"gitlab.com/wpetit/goweb/service"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Backend struct {
|
|
|
|
ctn *service.Container
|
|
|
|
username string
|
|
|
|
password string
|
|
|
|
}
|
|
|
|
|
|
|
|
// Login handles a login command with username and password.
|
|
|
|
func (b *Backend) Login(state *smtp.ConnectionState, username, password string) (smtp.Session, error) {
|
|
|
|
if b.username != "" && username != b.username {
|
|
|
|
return nil, errors.New("invalid username")
|
|
|
|
}
|
|
|
|
|
|
|
|
if b.password != "" && password != b.password {
|
|
|
|
return nil, errors.New("invalid password")
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx := context.WithValue(context.Background(), container.KeyServiceContainer, b.ctn)
|
|
|
|
|
|
|
|
return &Session{ctx, b.ctn, username}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// AnonymousLogin requires clients to authenticate using SMTP AUTH before sending emails
|
|
|
|
func (b *Backend) AnonymousLogin(state *smtp.ConnectionState) (smtp.Session, error) {
|
|
|
|
if b.username != "" || b.password != "" {
|
|
|
|
return nil, smtp.ErrAuthRequired
|
|
|
|
}
|
|
|
|
|
2020-06-17 23:48:32 +02:00
|
|
|
ctx := context.WithValue(context.Background(), container.KeyServiceContainer, b.ctn)
|
|
|
|
|
|
|
|
return &Session{ctx, b.ctn, "anonymous"}, nil
|
2020-04-17 17:53:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// A Session is returned after successful login.
|
|
|
|
type Session struct {
|
|
|
|
ctx context.Context
|
|
|
|
ctn *service.Container
|
|
|
|
username string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Session) Mail(from string, opts smtp.MailOptions) error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Session) Rcpt(to string) error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Session) Data(r io.Reader) error {
|
|
|
|
env, err := enmime.ReadEnvelope(r)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "could not read envelope")
|
|
|
|
}
|
|
|
|
|
|
|
|
bus, err := cqrs.From(s.ctn)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "could not retrieve cqrs service")
|
|
|
|
}
|
|
|
|
|
2020-11-05 19:48:18 +01:00
|
|
|
conf, err := config.From(s.ctn)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "could not retrieve config service")
|
|
|
|
}
|
|
|
|
|
|
|
|
if conf.Relay.Enabled {
|
|
|
|
cmd := &command.RelayEmailRequest{
|
|
|
|
Envelope: env,
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := bus.Exec(s.ctx, cmd); err != nil {
|
|
|
|
logger.Error(s.ctx, "could not exec command", logger.E(err))
|
|
|
|
|
|
|
|
return errors.Wrapf(err, "could not exec '%T' command", cmd)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-17 17:53:01 +02:00
|
|
|
cmd := &command.StoreEmailRequest{
|
|
|
|
Envelope: env,
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := bus.Exec(s.ctx, cmd); err != nil {
|
2020-11-05 19:48:18 +01:00
|
|
|
logger.Error(s.ctx, "could not exec command", logger.E(err))
|
|
|
|
|
|
|
|
return errors.Wrapf(err, "could not exec '%T' command", cmd)
|
2020-04-17 17:53:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Session) Reset() {}
|
|
|
|
|
|
|
|
func (s *Session) Logout() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func startSMTPServer(conf *config.Config, ctn *service.Container) {
|
|
|
|
be := &Backend{
|
|
|
|
ctn: ctn,
|
|
|
|
username: conf.SMTP.Username,
|
|
|
|
password: conf.SMTP.Password,
|
|
|
|
}
|
|
|
|
|
|
|
|
s := smtp.NewServer(be)
|
|
|
|
|
|
|
|
s.Addr = conf.SMTP.Address
|
|
|
|
s.Domain = conf.SMTP.Domain
|
|
|
|
s.ReadTimeout = conf.SMTP.ReadTimeout
|
|
|
|
s.WriteTimeout = conf.SMTP.WriteTimeout
|
|
|
|
s.MaxMessageBytes = conf.SMTP.MaxMessageBytes
|
|
|
|
s.MaxRecipients = conf.SMTP.MaxRecipients
|
|
|
|
s.AllowInsecureAuth = conf.SMTP.AllowInsecureAuth
|
2020-06-17 23:48:32 +02:00
|
|
|
|
|
|
|
if conf.SMTP.Username == "" && conf.SMTP.Password == "" {
|
|
|
|
s.AuthDisabled = true
|
|
|
|
}
|
|
|
|
|
2020-04-17 17:53:01 +02:00
|
|
|
if conf.SMTP.Debug {
|
|
|
|
s.Debug = os.Stdout
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Println("starting server at", s.Addr)
|
|
|
|
if err := s.ListenAndServe(); err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|