diff --git a/cmd/yggmail/main.go b/cmd/yggmail/main.go index 16b74a6..e105b20 100644 --- a/cmd/yggmail/main.go +++ b/cmd/yggmail/main.go @@ -23,6 +23,7 @@ import ( "github.com/neilalexander/yggmail/internal/smtpserver" "github.com/neilalexander/yggmail/internal/storage/sqlite3" "github.com/neilalexander/yggmail/internal/transport" + "github.com/neilalexander/yggmail/internal/utils" ) var database = flag.String("database", "yggmail.db", "SQLite database file") @@ -93,7 +94,7 @@ func main() { panic(err) } fmt.Printf("Created user %q\n", *createuser) - fmt.Printf("Email address will be %s@%s%s\n", *createuser, base62.EncodeToString(pk), smtpserver.TLD) + fmt.Printf("Email address will be %s@%s%s\n", *createuser, base62.EncodeToString(pk), utils.TLD) os.Exit(0) } diff --git a/internal/imapserver/backend.go b/internal/imapserver/backend.go index eadf2b6..458305e 100644 --- a/internal/imapserver/backend.go +++ b/internal/imapserver/backend.go @@ -6,8 +6,10 @@ import ( "github.com/emersion/go-imap" "github.com/emersion/go-imap/backend" + "github.com/jxskiss/base62" "github.com/neilalexander/yggmail/internal/config" "github.com/neilalexander/yggmail/internal/storage" + "github.com/neilalexander/yggmail/internal/utils" ) type Backend struct { @@ -17,6 +19,14 @@ type Backend struct { } func (b *Backend) Login(_ *imap.ConnInfo, username, password string) (backend.User, error) { + // If our username is email-like, then take just the localpart + if localpart, host, err := utils.ParseAddress(username); err == nil { + if host != base62.EncodeToString(b.Config.PublicKey) { + return nil, fmt.Errorf("failed to authenticate: wrong domain in username") + } + username = localpart + } + if authed, err := b.Storage.TryAuthenticate(username, password); err != nil { b.Log.Printf("Failed to authenticate IMAP user %q due to error: %s", username, err) return nil, fmt.Errorf("failed to authenticate: %w", err) diff --git a/internal/imapserver/mailbox.go b/internal/imapserver/mailbox.go index 73ff288..09c5d21 100644 --- a/internal/imapserver/mailbox.go +++ b/internal/imapserver/mailbox.go @@ -111,13 +111,9 @@ func (mbox *Mailbox) ListMessages(uid bool, seqSet *imap.SeqSet, items []imap.Fe ids, err := mbox.getIDsFromSeqSet(uid, seqSet) if err != nil { - fmt.Println("Failed to get IDs from sequences:", err) return fmt.Errorf("mbox.getIDsFromSeqSet: %w", err) } - fmt.Println("FETCHING", ids, uid) - fmt.Println("SEQ SET", seqSet) - for _, id := range ids { mseq, mid, body, seen, answered, flagged, deleted, datetime, err := mbox.backend.Storage.MailSelect(mbox.user.username, mbox.name, int(id)) if err != nil { diff --git a/internal/smtpserver/backend.go b/internal/smtpserver/backend.go index 13f34ae..5bd5167 100644 --- a/internal/smtpserver/backend.go +++ b/internal/smtpserver/backend.go @@ -10,6 +10,7 @@ import ( "github.com/neilalexander/yggmail/internal/config" "github.com/neilalexander/yggmail/internal/smtpsender" "github.com/neilalexander/yggmail/internal/storage" + "github.com/neilalexander/yggmail/internal/utils" ) type BackendMode int @@ -30,6 +31,14 @@ type Backend struct { func (b *Backend) Login(state *smtp.ConnectionState, username, password string) (smtp.Session, error) { switch b.Mode { case BackendModeInternal: + // If our username is email-like, then take just the localpart + if localpart, host, err := utils.ParseAddress(username); err == nil { + if host != base62.EncodeToString(b.Config.PublicKey) { + return nil, fmt.Errorf("failed to authenticate: wrong domain in username") + } + username = localpart + } + // The connection came from our local listener if authed, err := b.Storage.TryAuthenticate(username, password); err != nil { b.Log.Printf("Failed to authenticate SMTP user %q due to error: %s", username, err) diff --git a/internal/smtpserver/session_local.go b/internal/smtpserver/session_local.go index e1986bb..a2236ca 100644 --- a/internal/smtpserver/session_local.go +++ b/internal/smtpserver/session_local.go @@ -10,6 +10,7 @@ import ( "github.com/emersion/go-smtp" "github.com/jxskiss/base62" "github.com/neilalexander/yggmail/internal/smtpsender" + "github.com/neilalexander/yggmail/internal/utils" ) type SessionLocal struct { @@ -20,7 +21,7 @@ type SessionLocal struct { } func (s *SessionLocal) Mail(from string, opts smtp.MailOptions) error { - _, host, err := parseAddress(from) + _, host, err := utils.ParseAddress(from) if err != nil { return fmt.Errorf("parseAddress: %w", err) } @@ -55,7 +56,7 @@ func (s *SessionLocal) Data(r io.Reader) error { servers := make(map[string]struct{}) for _, rcpt := range s.rcpt { - localpart, host, err := parseAddress(rcpt) + localpart, host, err := utils.ParseAddress(rcpt) if err != nil { return fmt.Errorf("parseAddress: %w", err) } diff --git a/internal/smtpserver/session_remote.go b/internal/smtpserver/session_remote.go index 5c1f5cf..4a7427a 100644 --- a/internal/smtpserver/session_remote.go +++ b/internal/smtpserver/session_remote.go @@ -11,6 +11,7 @@ import ( "github.com/emersion/go-message" "github.com/emersion/go-smtp" "github.com/jxskiss/base62" + "github.com/neilalexander/yggmail/internal/utils" ) type SessionRemote struct { @@ -22,7 +23,7 @@ type SessionRemote struct { } func (s *SessionRemote) Mail(from string, opts smtp.MailOptions) error { - _, host, err := parseAddress(from) + _, host, err := utils.ParseAddress(from) if err != nil { return fmt.Errorf("mail.ParseAddress: %w", err) } @@ -41,7 +42,7 @@ func (s *SessionRemote) Mail(from string, opts smtp.MailOptions) error { } func (s *SessionRemote) Rcpt(to string) error { - user, host, err := parseAddress(to) + user, host, err := utils.ParseAddress(to) if err != nil { return fmt.Errorf("mail.ParseAddress: %w", err) } diff --git a/internal/smtpserver/session.go b/internal/utils/address.go similarity index 80% rename from internal/smtpserver/session.go rename to internal/utils/address.go index da2bc82..934138b 100644 --- a/internal/smtpserver/session.go +++ b/internal/utils/address.go @@ -1,4 +1,4 @@ -package smtpserver +package utils import ( "fmt" @@ -7,7 +7,7 @@ import ( const TLD = ".yggmail" -func parseAddress(email string) (string, string, error) { +func ParseAddress(email string) (string, string, error) { if !strings.HasSuffix(email, TLD) { return "", "", fmt.Errorf("invalid TLD") }