aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Ser <contact@emersion.fr>2019-12-09 18:35:51 +0100
committerSimon Ser <contact@emersion.fr>2019-12-09 18:35:51 +0100
commit7702925497a8230f50d2317c9ad41a73de0683ae (patch)
tree617955544543a71baf5c17134a422c0e8fd16bbf
parentefd401bfbf62b2216fe92b4d8be8c07e77b78482 (diff)
downloadalps-7702925497a8230f50d2317c9ad41a73de0683ae.tar.gz
alps-7702925497a8230f50d2317c9ad41a73de0683ae.zip
Make SessionManager create the IMAP client
This will allow SessionManager to re-connect when the IMAP server logs the user out.
-rw-r--r--handlers.go15
-rw-r--r--plugin.go6
-rw-r--r--server.go2
-rw-r--r--session.go46
4 files changed, 46 insertions, 23 deletions
diff --git a/handlers.go b/handlers.go
index 8dc3fbf..869e1c1 100644
--- a/handlers.go
+++ b/handlers.go
@@ -81,18 +81,11 @@ func handleLogin(ectx echo.Context) error {
username := ctx.FormValue("username")
password := ctx.FormValue("password")
if username != "" && password != "" {
- conn, err := ctx.server.connectIMAP()
- 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)
+ token, err := ctx.server.sessions.Put(username, password)
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)
}
ctx.setToken(token)
diff --git a/plugin.go b/plugin.go
index 26473b1..9464d60 100644
--- a/plugin.go
+++ b/plugin.go
@@ -38,15 +38,15 @@ func (p *luaPlugin) onRender(l *lua.LState) int {
func (p *luaPlugin) setFilter(l *lua.LState) int {
name := l.CheckString(1)
f := l.CheckFunction(2)
- p.filters[name] = func(args... interface{}) string {
+ p.filters[name] = func(args ...interface{}) string {
luaArgs := make([]lua.LValue, len(args))
for i, v := range args {
luaArgs[i] = luar.New(l, v)
}
err := l.CallByParam(lua.P{
- Fn: f,
- NRet: 1,
+ Fn: f,
+ NRet: 1,
Protect: true,
}, luaArgs...)
if err != nil {
diff --git a/server.go b/server.go
index a0ac1d3..94cc133 100644
--- a/server.go
+++ b/server.go
@@ -76,7 +76,7 @@ func (s *Server) parseSMTPURL(smtpURL string) error {
func newServer(imapURL, smtpURL string) (*Server, error) {
s := &Server{}
- s.sessions = NewSessionManager()
+ s.sessions = NewSessionManager(s.connectIMAP)
if err := s.parseIMAPURL(imapURL); err != nil {
return nil, err
diff --git a/session.go b/session.go
index 0aa5d5f..0292d3a 100644
--- a/session.go
+++ b/session.go
@@ -4,6 +4,7 @@ import (
"crypto/rand"
"encoding/base64"
"errors"
+ "fmt"
"sync"
imapclient "github.com/emersion/go-imap/client"
@@ -20,6 +21,14 @@ func generateToken() (string, error) {
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 {
locker sync.Mutex
imapConn *imapclient.Client
@@ -35,16 +44,32 @@ func (s *Session) Do(f func(*imapclient.Client) error) error {
// TODO: expiration timer
type SessionManager struct {
- locker sync.Mutex
- sessions map[string]*Session
+ locker sync.Mutex
+ sessions map[string]*Session
+ newIMAPClient func() (*imapclient.Client, error)
}
-func NewSessionManager() *SessionManager {
+func NewSessionManager(newIMAPClient func() (*imapclient.Client, error)) *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) {
sm.locker.Lock()
defer sm.locker.Unlock()
@@ -56,7 +81,12 @@ func (sm *SessionManager) Get(token string) (*Session, error) {
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()
defer sm.locker.Unlock()
@@ -64,7 +94,7 @@ func (sm *SessionManager) Put(imapConn *imapclient.Client, username, password st
var err error
token, err = generateToken()
if err != nil {
- imapConn.Logout()
+ c.Logout()
return "", err
}
@@ -74,13 +104,13 @@ func (sm *SessionManager) Put(imapConn *imapclient.Client, username, password st
}
sm.sessions[token] = &Session{
- imapConn: imapConn,
+ imapConn: c,
username: username,
password: password,
}
go func() {
- <-imapConn.LoggedOut()
+ <-c.LoggedOut()
sm.locker.Lock()
delete(sm.sessions, token)