initial
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
// Package imap provides an IMAP4rev2 server backed by the encrypted SQLite store.
|
||||
package imap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/emersion/go-imap/v2"
|
||||
"github.com/emersion/go-imap/v2/imapserver"
|
||||
|
||||
"ghb.freebede.com/nahakubuilder/mailgosend/internal/auth"
|
||||
"ghb.freebede.com/nahakubuilder/mailgosend/internal/config"
|
||||
appCrypto "ghb.freebede.com/nahakubuilder/mailgosend/internal/crypto"
|
||||
"ghb.freebede.com/nahakubuilder/mailgosend/internal/db"
|
||||
)
|
||||
|
||||
// Deps groups dependencies needed by the IMAP server.
|
||||
type Deps struct {
|
||||
DB *db.DB
|
||||
Crypt *appCrypto.Crypto
|
||||
Brute *auth.BruteGuard
|
||||
Cfg *config.Config
|
||||
}
|
||||
|
||||
// NewServer creates an IMAP4rev2 server for port 143 (STARTTLS).
|
||||
func NewServer(d *Deps, tlsCfg *tls.Config) *imapserver.Server {
|
||||
return imapserver.New(&imapserver.Options{
|
||||
NewSession: func(c *imapserver.Conn) (imapserver.Session, *imapserver.GreetingData, error) {
|
||||
clientIP := connRemoteIP(c)
|
||||
if d.Brute != nil && d.Cfg.BruteMaxTries > 0 {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
if banned, err := d.Brute.IsBanned(ctx, clientIP); err == nil && banned {
|
||||
cancel()
|
||||
return nil, nil, fmt.Errorf("connection refused")
|
||||
}
|
||||
cancel()
|
||||
}
|
||||
return &IMAPSession{deps: d, clientIP: clientIP}, &imapserver.GreetingData{}, nil
|
||||
},
|
||||
Caps: imap.CapSet{
|
||||
imap.CapIMAP4rev2: {},
|
||||
imap.CapIMAP4rev1: {},
|
||||
},
|
||||
TLSConfig: tlsCfg,
|
||||
InsecureAuth: tlsCfg == nil,
|
||||
})
|
||||
}
|
||||
|
||||
// ListenAndServe listens on addr (port 143 / STARTTLS).
|
||||
func ListenAndServe(s *imapserver.Server, addr, name string) error {
|
||||
ln, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s listen %s: %w", name, addr, err)
|
||||
}
|
||||
log.Printf("[%s] listening on %s", name, addr)
|
||||
return s.Serve(ln)
|
||||
}
|
||||
|
||||
// ListenAndServeTLS listens with implicit TLS (port 993 / IMAPS).
|
||||
func ListenAndServeTLS(s *imapserver.Server, addr, name string) error {
|
||||
log.Printf("[%s] listening on %s (TLS)", name, addr)
|
||||
return s.ListenAndServeTLS(addr)
|
||||
}
|
||||
|
||||
// connRemoteIP returns the client IP from an imapserver.Conn.
|
||||
func connRemoteIP(c *imapserver.Conn) string {
|
||||
if c == nil {
|
||||
return ""
|
||||
}
|
||||
nc := c.NetConn()
|
||||
if nc == nil {
|
||||
return ""
|
||||
}
|
||||
host, _, _ := net.SplitHostPort(nc.RemoteAddr().String())
|
||||
return host
|
||||
}
|
||||
Reference in New Issue
Block a user