package main import ( "crypto/ed25519" "errors" "github.com/emersion/go-imap/v2/imapserver" "github.com/google/uuid" "sync" ) // OAuthConfig is the configuration for OAuth. type OAuthConfig struct { HostName string PublicKey ed25519.PublicKey } // Server is a server instance. // // A server contains a list of users. type Server struct { config OAuthConfig userMutex sync.Mutex users map[uuid.UUID]*User } // New creates a new server. func New(config OAuthConfig) *Server { return &Server{ config: config, users: make(map[uuid.UUID]*User), } } func (s *Server) userRaw(sub uuid.UUID) (*User, error) { s.userMutex.Lock() defer s.userMutex.Unlock() user, ok := s.users[sub] if !ok { user = &User{ mailboxes: make(map[string]*Mailbox), sessions: make(map[*UserSession]struct{}), server: s, sub: sub, } s.users[sub] = user _, err := user.mailbox("INBOX") if err != nil { if errors.Is(err, ErrNoSuchMailbox) { err := user.Create("INBOX", nil) if err != nil { return nil, err } } else { return nil, err } } } return user, nil } func (s *Server) user(token string) (*User, error) { sub, err := Authenticate(token, s.config) if err != nil { return nil, err } return s.userRaw(sub) } // NewSession creates a new IMAP session. func (s *Server) NewSession() imapserver.Session { return s.newSession() } func (s *Server) newSession() *EntryPoint { return &EntryPoint{ Server: s, } }