From 00542af08db0c23dee6c63de4b2bddc1058248a8 Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 3 Dec 2017 14:58:24 +0100 Subject: [PATCH] Spin up imap server skeleton --- cmd/hydroxide/hydroxide.go | 19 ++++++++- imap/imap.go | 80 ++++++++++++++++++++++++++++++++++++++ smtp/smtp.go | 1 + 3 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 imap/imap.go diff --git a/cmd/hydroxide/hydroxide.go b/cmd/hydroxide/hydroxide.go index af2d2ac..ad824a6 100644 --- a/cmd/hydroxide/hydroxide.go +++ b/cmd/hydroxide/hydroxide.go @@ -10,12 +10,14 @@ import ( "os" "time" + imapserver "github.com/emersion/go-imap/server" "github.com/emersion/go-smtp" "github.com/howeyc/gopass" "github.com/emersion/hydroxide/auth" "github.com/emersion/hydroxide/carddav" "github.com/emersion/hydroxide/protonmail" + imapbackend "github.com/emersion/hydroxide/imap" smtpbackend "github.com/emersion/hydroxide/smtp" ) @@ -135,7 +137,7 @@ func main() { case "smtp": port := os.Getenv("PORT") if port == "" { - port = "1465" + port = "1025" } sessions := auth.NewManager(newClient) @@ -148,6 +150,21 @@ func main() { log.Println("Starting SMTP server at", s.Addr) log.Fatal(s.ListenAndServe()) + case "imap": + port := os.Getenv("PORT") + if port == "" { + port = "1143" + } + + sessions := auth.NewManager(newClient) + + be := imapbackend.New(sessions) + s := imapserver.New(be) + s.Addr = "127.0.0.1:" + port + s.AllowInsecureAuth = true // TODO: remove this + + log.Println("Starting IMAP server at", s.Addr) + log.Fatal(s.ListenAndServe()) case "carddav": port := os.Getenv("PORT") if port == "" { diff --git a/imap/imap.go b/imap/imap.go new file mode 100644 index 0000000..d13cc4a --- /dev/null +++ b/imap/imap.go @@ -0,0 +1,80 @@ +package imap + +import ( + "errors" + + imapbackend "github.com/emersion/go-imap/backend" + "golang.org/x/crypto/openpgp" + + "github.com/emersion/hydroxide/auth" + "github.com/emersion/hydroxide/protonmail" +) + +var errNotYetImplemented = errors.New("not yet implemented") + +type user struct { + username string + c *protonmail.Client + u *protonmail.User + privateKeys openpgp.EntityList +} + +func (u *user) Username() string { + return u.username +} + +func (u *user) ListMailboxes(subscribed bool) ([]imapbackend.Mailbox, error) { + return nil, errNotYetImplemented // TODO +} + +func (u *user) GetMailbox(name string) (imapbackend.Mailbox, error) { + return nil, errNotYetImplemented // TODO +} + +func (u *user) CreateMailbox(name string) error { + return errNotYetImplemented // TODO +} + +func (u *user) DeleteMailbox(name string) error { + return errNotYetImplemented // TODO +} + +func (u *user) RenameMailbox(existingName, newName string) error { + return errNotYetImplemented // TODO +} + +func (u *user) Logout() error { + u.c = nil + u.u = nil + u.privateKeys = nil + return nil +} + +type backend struct { + sessions *auth.Manager +} + +func (be *backend) Login(username, password string) (imapbackend.User, error) { + c, privateKeys, err := be.sessions.Auth(username, password) + if err != nil { + return nil, err + } + + u, err := c.GetCurrentUser() + if err != nil { + return nil, err + } + + // TODO: decrypt private keys in u.Addresses + + return &user{ + username: username, + c: c, + u: u, + privateKeys: privateKeys, + }, nil +} + +func New(sessions *auth.Manager) imapbackend.Backend { + return &backend{sessions} +} diff --git a/smtp/smtp.go b/smtp/smtp.go index af6a8e2..21ef144 100644 --- a/smtp/smtp.go +++ b/smtp/smtp.go @@ -310,6 +310,7 @@ func (u *user) Send(from string, to []string, r io.Reader) error { func (u *user) Logout() error { u.c = nil + u.u = nil u.privateKeys = nil return nil }