Make SessionManager create the IMAP client
This will allow SessionManager to re-connect when the IMAP server logs the user out.
This commit is contained in:
parent
efd401bfbf
commit
7702925497
15
handlers.go
15
handlers.go
|
@ -81,18 +81,11 @@ func handleLogin(ectx echo.Context) error {
|
||||||
username := ctx.FormValue("username")
|
username := ctx.FormValue("username")
|
||||||
password := ctx.FormValue("password")
|
password := ctx.FormValue("password")
|
||||||
if username != "" && password != "" {
|
if username != "" && password != "" {
|
||||||
conn, err := ctx.server.connectIMAP()
|
token, err := ctx.server.sessions.Put(username, password)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := conn.Login(username, password); err != nil {
|
|
||||||
conn.Logout()
|
|
||||||
return ctx.Render(http.StatusOK, "login.html", nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
token, err := ctx.server.sessions.Put(conn, username, password)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if _, ok := err.(AuthError); ok {
|
||||||
|
return ctx.Render(http.StatusOK, "login.html", nil)
|
||||||
|
}
|
||||||
return fmt.Errorf("failed to put connection in pool: %v", err)
|
return fmt.Errorf("failed to put connection in pool: %v", err)
|
||||||
}
|
}
|
||||||
ctx.setToken(token)
|
ctx.setToken(token)
|
||||||
|
|
|
@ -38,15 +38,15 @@ func (p *luaPlugin) onRender(l *lua.LState) int {
|
||||||
func (p *luaPlugin) setFilter(l *lua.LState) int {
|
func (p *luaPlugin) setFilter(l *lua.LState) int {
|
||||||
name := l.CheckString(1)
|
name := l.CheckString(1)
|
||||||
f := l.CheckFunction(2)
|
f := l.CheckFunction(2)
|
||||||
p.filters[name] = func(args... interface{}) string {
|
p.filters[name] = func(args ...interface{}) string {
|
||||||
luaArgs := make([]lua.LValue, len(args))
|
luaArgs := make([]lua.LValue, len(args))
|
||||||
for i, v := range args {
|
for i, v := range args {
|
||||||
luaArgs[i] = luar.New(l, v)
|
luaArgs[i] = luar.New(l, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := l.CallByParam(lua.P{
|
err := l.CallByParam(lua.P{
|
||||||
Fn: f,
|
Fn: f,
|
||||||
NRet: 1,
|
NRet: 1,
|
||||||
Protect: true,
|
Protect: true,
|
||||||
}, luaArgs...)
|
}, luaArgs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -76,7 +76,7 @@ func (s *Server) parseSMTPURL(smtpURL string) error {
|
||||||
|
|
||||||
func newServer(imapURL, smtpURL string) (*Server, error) {
|
func newServer(imapURL, smtpURL string) (*Server, error) {
|
||||||
s := &Server{}
|
s := &Server{}
|
||||||
s.sessions = NewSessionManager()
|
s.sessions = NewSessionManager(s.connectIMAP)
|
||||||
|
|
||||||
if err := s.parseIMAPURL(imapURL); err != nil {
|
if err := s.parseIMAPURL(imapURL); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
46
session.go
46
session.go
|
@ -4,6 +4,7 @@ import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
imapclient "github.com/emersion/go-imap/client"
|
imapclient "github.com/emersion/go-imap/client"
|
||||||
|
@ -20,6 +21,14 @@ func generateToken() (string, error) {
|
||||||
|
|
||||||
var ErrSessionExpired = errors.New("session expired")
|
var ErrSessionExpired = errors.New("session expired")
|
||||||
|
|
||||||
|
type AuthError struct {
|
||||||
|
cause error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err AuthError) Error() string {
|
||||||
|
return fmt.Sprintf("authentication failed: %v", err.cause)
|
||||||
|
}
|
||||||
|
|
||||||
type Session struct {
|
type Session struct {
|
||||||
locker sync.Mutex
|
locker sync.Mutex
|
||||||
imapConn *imapclient.Client
|
imapConn *imapclient.Client
|
||||||
|
@ -35,16 +44,32 @@ func (s *Session) Do(f func(*imapclient.Client) error) error {
|
||||||
|
|
||||||
// TODO: expiration timer
|
// TODO: expiration timer
|
||||||
type SessionManager struct {
|
type SessionManager struct {
|
||||||
locker sync.Mutex
|
locker sync.Mutex
|
||||||
sessions map[string]*Session
|
sessions map[string]*Session
|
||||||
|
newIMAPClient func() (*imapclient.Client, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSessionManager() *SessionManager {
|
func NewSessionManager(newIMAPClient func() (*imapclient.Client, error)) *SessionManager {
|
||||||
return &SessionManager{
|
return &SessionManager{
|
||||||
sessions: make(map[string]*Session),
|
sessions: make(map[string]*Session),
|
||||||
|
newIMAPClient: newIMAPClient,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sm *SessionManager) connect(username, password string) (*imapclient.Client, error) {
|
||||||
|
c, err := sm.newIMAPClient()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.Login(username, password); err != nil {
|
||||||
|
c.Logout()
|
||||||
|
return nil, AuthError{err}
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (sm *SessionManager) Get(token string) (*Session, error) {
|
func (sm *SessionManager) Get(token string) (*Session, error) {
|
||||||
sm.locker.Lock()
|
sm.locker.Lock()
|
||||||
defer sm.locker.Unlock()
|
defer sm.locker.Unlock()
|
||||||
|
@ -56,7 +81,12 @@ func (sm *SessionManager) Get(token string) (*Session, error) {
|
||||||
return session, nil
|
return session, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *SessionManager) Put(imapConn *imapclient.Client, username, password string) (token string, err error) {
|
func (sm *SessionManager) Put(username, password string) (token string, err error) {
|
||||||
|
c, err := sm.connect(username, password)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
sm.locker.Lock()
|
sm.locker.Lock()
|
||||||
defer sm.locker.Unlock()
|
defer sm.locker.Unlock()
|
||||||
|
|
||||||
|
@ -64,7 +94,7 @@ func (sm *SessionManager) Put(imapConn *imapclient.Client, username, password st
|
||||||
var err error
|
var err error
|
||||||
token, err = generateToken()
|
token, err = generateToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
imapConn.Logout()
|
c.Logout()
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,13 +104,13 @@ func (sm *SessionManager) Put(imapConn *imapclient.Client, username, password st
|
||||||
}
|
}
|
||||||
|
|
||||||
sm.sessions[token] = &Session{
|
sm.sessions[token] = &Session{
|
||||||
imapConn: imapConn,
|
imapConn: c,
|
||||||
username: username,
|
username: username,
|
||||||
password: password,
|
password: password,
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
<-imapConn.LoggedOut()
|
<-c.LoggedOut()
|
||||||
|
|
||||||
sm.locker.Lock()
|
sm.locker.Lock()
|
||||||
delete(sm.sessions, token)
|
delete(sm.sessions, token)
|
||||||
|
|
Loading…
Reference in a new issue