Save username/password in session

This is required for authenticating with the SMTP server when composing
a new message.
This commit is contained in:
Simon Ser 2019-12-03 15:44:20 +01:00
parent ae79f99876
commit 702719c072
No known key found for this signature in database
GPG key ID: 0FDE7BE0E88F5E48
2 changed files with 26 additions and 13 deletions

View file

@ -20,30 +20,35 @@ func generateToken() (string, error) {
var ErrSessionExpired = errors.New("session expired") var ErrSessionExpired = errors.New("session expired")
type Session struct {
imapConn *imapclient.Client
username, password string
}
// TODO: expiration timer // TODO: expiration timer
type ConnPool struct { type ConnPool struct {
locker sync.Mutex locker sync.Mutex
conns map[string]*imapclient.Client sessions map[string]*Session
} }
func NewConnPool() *ConnPool { func NewConnPool() *ConnPool {
return &ConnPool{ return &ConnPool{
conns: make(map[string]*imapclient.Client), sessions: make(map[string]*Session),
} }
} }
func (pool *ConnPool) Get(token string) (*imapclient.Client, error) { func (pool *ConnPool) Get(token string) (*Session, error) {
pool.locker.Lock() pool.locker.Lock()
defer pool.locker.Unlock() defer pool.locker.Unlock()
conn, ok := pool.conns[token] session, ok := pool.sessions[token]
if !ok { if !ok {
return nil, ErrSessionExpired return nil, ErrSessionExpired
} }
return conn, nil return session, nil
} }
func (pool *ConnPool) Put(conn *imapclient.Client) (token string, err error) { func (pool *ConnPool) Put(imapConn *imapclient.Client, username, password string) (token string, err error) {
pool.locker.Lock() pool.locker.Lock()
defer pool.locker.Unlock() defer pool.locker.Unlock()
@ -51,22 +56,26 @@ func (pool *ConnPool) Put(conn *imapclient.Client) (token string, err error) {
var err error var err error
token, err = generateToken() token, err = generateToken()
if err != nil { if err != nil {
conn.Logout() imapConn.Logout()
return "", err return "", err
} }
if _, ok := pool.conns[token]; !ok { if _, ok := pool.sessions[token]; !ok {
break break
} }
} }
pool.conns[token] = conn pool.sessions[token] = &Session{
imapConn: imapConn,
username: username,
password: password,
}
go func() { go func() {
<-conn.LoggedOut() <-imapConn.LoggedOut()
pool.locker.Lock() pool.locker.Lock()
delete(pool.conns, token) delete(pool.sessions, token)
pool.locker.Unlock() pool.locker.Unlock()
}() }()

View file

@ -93,6 +93,7 @@ func NewServer(imapURL, smtpURL string) (*Server, error) {
type context struct { type context struct {
echo.Context echo.Context
server *Server server *Server
session *Session
conn *imapclient.Client conn *imapclient.Client
} }
@ -126,7 +127,7 @@ func handleLogin(ectx echo.Context) error {
return ctx.Render(http.StatusOK, "login.html", nil) return ctx.Render(http.StatusOK, "login.html", nil)
} }
token, err := ctx.server.imap.pool.Put(conn) token, err := ctx.server.imap.pool.Put(conn, username, password)
if err != nil { if err != nil {
return fmt.Errorf("failed to put connection in pool: %v", err) return fmt.Errorf("failed to put connection in pool: %v", err)
} }
@ -167,6 +168,8 @@ func handleGetPart(ctx *context, raw bool) error {
disp, dispParams, _ := part.Header.ContentDisposition() disp, dispParams, _ := part.Header.ContentDisposition()
filename := dispParams["filename"] filename := dispParams["filename"]
// TODO: set Content-Length if possible
if !strings.EqualFold(mimeType, "text/plain") || strings.EqualFold(disp, "attachment") { if !strings.EqualFold(mimeType, "text/plain") || strings.EqualFold(disp, "attachment") {
dispParams := make(map[string]string) dispParams := make(map[string]string)
if filename != "" { if filename != "" {
@ -235,13 +238,14 @@ func New(imapURL, smtpURL string) *echo.Echo {
return err return err
} }
ctx.conn, err = ctx.server.imap.pool.Get(cookie.Value) ctx.session, err = ctx.server.imap.pool.Get(cookie.Value)
if err == ErrSessionExpired { if err == ErrSessionExpired {
ctx.setToken("") ctx.setToken("")
return ctx.Redirect(http.StatusFound, "/login") return ctx.Redirect(http.StatusFound, "/login")
} else if err != nil { } else if err != nil {
return err return err
} }
ctx.conn = ctx.session.imapConn
return next(ctx) return next(ctx)
} }