fake-smtp/cmd/fake-smtp/smtp.go

117 lines
2.6 KiB
Go

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"
"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
}
return nil, nil
}
// 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")
}
cmd := &command.StoreEmailRequest{
Envelope: env,
}
if _, err := bus.Exec(s.ctx, cmd); err != nil {
return errors.Wrap(err, "could not exec command")
}
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
if conf.SMTP.Debug {
s.Debug = os.Stdout
}
log.Println("starting server at", s.Addr)
if err := s.ListenAndServe(); err != nil {
log.Fatal(err)
}
}