forked from Silverfish/proton-bridge
feat(BRIDGE-205): add support for the IMAP AUTHENTICATE command.
This commit is contained in:
2
go.mod
2
go.mod
@ -7,7 +7,7 @@ toolchain go1.21.9
|
||||
require (
|
||||
github.com/0xAX/notificator v0.0.0-20220220101646-ee9b8921e557
|
||||
github.com/Masterminds/semver/v3 v3.2.0
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20241018144126-31e040c2417e
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20241112142609-f4ac4c4fbbce
|
||||
github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a
|
||||
github.com/ProtonMail/go-proton-api v0.4.1-0.20240918100656-b4860af56d47
|
||||
github.com/ProtonMail/gopenpgp/v2 v2.7.4-proton
|
||||
|
||||
6
go.sum
6
go.sum
@ -48,6 +48,12 @@ github.com/ProtonMail/gluon v0.17.1-0.20241014082854-9d93627be032 h1:5bwI+mwF26c
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20241014082854-9d93627be032/go.mod h1:0/c03TzZPNiSgY5UDJK1iRDkjlDPwWugxTT6et2qDu8=
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20241018144126-31e040c2417e h1:+UfdKOkF9JEiH9VXWBo+/nlXNVSJcxtuf4+SJTrk9fw=
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20241018144126-31e040c2417e/go.mod h1:0/c03TzZPNiSgY5UDJK1iRDkjlDPwWugxTT6et2qDu8=
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20241111071724-6536da14d087 h1:hqoJCo54y/4cO1w9ZfaqRMAvxdxJMRT0vc0ICbg8nVA=
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20241111071724-6536da14d087/go.mod h1:0/c03TzZPNiSgY5UDJK1iRDkjlDPwWugxTT6et2qDu8=
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20241112080731-83106972325c h1:+klUNkIb8TMXxnE80PDJM5YV2gPfmyOal3hiofdGSAs=
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20241112080731-83106972325c/go.mod h1:0/c03TzZPNiSgY5UDJK1iRDkjlDPwWugxTT6et2qDu8=
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20241112142609-f4ac4c4fbbce h1:lphIROziz1jya/E40KzWSDNm+tEyp86XkPk7qk1LgVY=
|
||||
github.com/ProtonMail/gluon v0.17.1-0.20241112142609-f4ac4c4fbbce/go.mod h1:0/c03TzZPNiSgY5UDJK1iRDkjlDPwWugxTT6et2qDu8=
|
||||
github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a h1:D+aZah+k14Gn6kmL7eKxoo/4Dr/lK3ChBcwce2+SQP4=
|
||||
github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230321155629-9a39f2531310/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE=
|
||||
|
||||
@ -13,26 +13,46 @@ Feature: A user can authenticate an IMAP client
|
||||
When user "[user:user]" connects IMAP client "1"
|
||||
Then IMAP client "1" can authenticate
|
||||
|
||||
Scenario: IMAP client can authenticate successfully using IMAP AUTHENTICATE
|
||||
When user "[user:user]" connects IMAP client "1"
|
||||
Then IMAP client "1" can authenticate using IMAP AUTHENTICATE
|
||||
|
||||
Scenario: IMAP client can authenticate successfully with different case
|
||||
When user "[user:user]" connects IMAP client "1"
|
||||
Then IMAP client "1" can authenticate with address "{toUpper:[user:user]@[domain]}"
|
||||
|
||||
Scenario: IMAP client can authenticate successfully with different case using IMAP AUTHENTICATE
|
||||
When user "[user:user]" connects IMAP client "1"
|
||||
Then IMAP client "1" can authenticate with address "{toUpper:[user:user]@[domain]}" using IMAP AUTHENTICATE
|
||||
|
||||
Scenario: IMAP client can authenticate successfully with secondary address
|
||||
Given user "[user:user]" connects and authenticates IMAP client "1" with address "[alias:alias]@[domain]"
|
||||
|
||||
Scenario: IMAP client can authenticate successfully
|
||||
When user "[user:user]" connects IMAP client "1"
|
||||
Then IMAP client "1" can authenticate
|
||||
Scenario: IMAP client can authenticate successfully with secondary address using IMAP AUTHENTICATE
|
||||
Given user "[user:user]" connects and authenticates IMAP client "1" with address "[alias:alias]@[domain]" using IMAP AUTHENTICATE
|
||||
|
||||
Scenario: IMAP client cannot authenticate with bad username
|
||||
When user "[user:user]" connects IMAP client "1"
|
||||
Then IMAP client "1" cannot authenticate with incorrect username
|
||||
|
||||
Scenario: IMAP client cannot authenticate with bad username using IMAP AUTHENTICATE
|
||||
When user "[user:user]" connects IMAP client "1"
|
||||
Then IMAP client "1" cannot authenticate with incorrect username using IMAP AUTHENTICATE
|
||||
|
||||
Scenario: IMAP client cannot authenticate with bad password
|
||||
When user "[user:user]" connects IMAP client "1"
|
||||
Then IMAP client "1" cannot authenticate with incorrect password
|
||||
|
||||
Scenario: IMAP client cannot authenticate with bad password using IMAP AUTHENTICATE
|
||||
When user "[user:user]" connects IMAP client "1"
|
||||
Then IMAP client "1" cannot authenticate with incorrect password using IMAP AUTHENTICATE
|
||||
|
||||
Scenario: IMAP client cannot authenticate for disconnected user
|
||||
When user "[user:user]" logs out
|
||||
And user "[user:user]" connects IMAP client "1"
|
||||
Then IMAP client "1" cannot authenticate
|
||||
|
||||
Scenario: IMAP client cannot authenticate using IMAP AUTHENTICATE for disconnected user
|
||||
When user "[user:user]" logs out
|
||||
And user "[user:user]" connects IMAP client "1"
|
||||
Then IMAP client "1" cannot authenticate using IMAP AUTHENTICATE
|
||||
|
||||
@ -36,10 +36,38 @@ import (
|
||||
"github.com/emersion/go-imap"
|
||||
id "github.com/emersion/go-imap-id"
|
||||
"github.com/emersion/go-imap/client"
|
||||
"github.com/emersion/go-sasl"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
type imapAuthMethod int
|
||||
|
||||
const (
|
||||
imapLogin imapAuthMethod = iota
|
||||
imapAuthenticate
|
||||
)
|
||||
|
||||
func (s *scenario) loginWithAuthMethod(client *client.Client, username, password string, authMethod imapAuthMethod) error {
|
||||
switch authMethod {
|
||||
case imapLogin:
|
||||
return client.Login(username, password)
|
||||
case imapAuthenticate:
|
||||
supported, err := client.SupportAuth(sasl.Plain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !supported {
|
||||
return errors.New("server does not support AUTHENTICATE PLAIN")
|
||||
}
|
||||
|
||||
return client.Authenticate(sasl.NewPlainClient("", username, password))
|
||||
default:
|
||||
return errors.New("unknown IMAP auth method")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *scenario) userConnectsIMAPClient(username, clientID string) error {
|
||||
return s.t.newIMAPClient(s.t.getUserByName(username).getUserID(), clientID)
|
||||
}
|
||||
@ -59,7 +87,17 @@ func (s *scenario) userConnectsAndAuthenticatesIMAPClientWithAddress(username, c
|
||||
|
||||
userID, client := s.t.getIMAPClient(clientID)
|
||||
|
||||
return client.Login(address, s.t.getUserByID(userID).getBridgePass())
|
||||
return s.loginWithAuthMethod(client, address, s.t.getUserByID(userID).getBridgePass(), imapLogin)
|
||||
}
|
||||
|
||||
func (s *scenario) userConnectsAndAuthenticatesIMAPClientWithAddressUsingIMAPAuthenticate(username, clientID, address string) error {
|
||||
if err := s.t.newIMAPClient(s.t.getUserByName(username).getUserID(), clientID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
userID, client := s.t.getIMAPClient(clientID)
|
||||
|
||||
return s.loginWithAuthMethod(client, address, s.t.getUserByID(userID).getBridgePass(), imapAuthenticate)
|
||||
}
|
||||
|
||||
func (s *scenario) userConnectsAndCanNotAuthenticateIMAPClientWithAddress(username, clientID, address string) error {
|
||||
@ -69,7 +107,7 @@ func (s *scenario) userConnectsAndCanNotAuthenticateIMAPClientWithAddress(userna
|
||||
|
||||
userID, client := s.t.getIMAPClient(clientID)
|
||||
|
||||
if err := client.Login(address, s.t.getUserByID(userID).getBridgePass()); err == nil {
|
||||
if err := s.loginWithAuthMethod(client, address, s.t.getUserByID(userID).getBridgePass(), imapLogin); err == nil {
|
||||
return fmt.Errorf("expected error, got nil")
|
||||
}
|
||||
|
||||
@ -79,19 +117,51 @@ func (s *scenario) userConnectsAndCanNotAuthenticateIMAPClientWithAddress(userna
|
||||
func (s *scenario) imapClientCanAuthenticate(clientID string) error {
|
||||
userID, client := s.t.getIMAPClient(clientID)
|
||||
|
||||
return client.Login(s.t.getUserByID(userID).getEmails()[0], s.t.getUserByID(userID).getBridgePass())
|
||||
return s.loginWithAuthMethod(client, s.t.getUserByID(userID).getEmails()[0], s.t.getUserByID(userID).getBridgePass(), imapLogin)
|
||||
}
|
||||
|
||||
func (s *scenario) imapClientCanAuthenticateUsingIMAPAuthenticate(clientID string) error {
|
||||
userID, client := s.t.getIMAPClient(clientID)
|
||||
|
||||
return s.loginWithAuthMethod(client, s.t.getUserByID(userID).getEmails()[0], s.t.getUserByID(userID).getBridgePass(), imapAuthenticate)
|
||||
}
|
||||
|
||||
func (s *scenario) imapClientCanAuthenticateWithAddress(clientID string, address string) error {
|
||||
userID, client := s.t.getIMAPClient(clientID)
|
||||
|
||||
return client.Login(address, s.t.getUserByID(userID).getBridgePass())
|
||||
return s.loginWithAuthMethod(client, address, s.t.getUserByID(userID).getBridgePass(), imapLogin)
|
||||
}
|
||||
|
||||
func (s *scenario) imapClientCanAuthenticateWithAddressUsingIMAPAuthenticate(clientID string, address string) error {
|
||||
userID, client := s.t.getIMAPClient(clientID)
|
||||
|
||||
return s.loginWithAuthMethod(client, address, s.t.getUserByID(userID).getBridgePass(), imapAuthenticate)
|
||||
}
|
||||
|
||||
func (s *scenario) imapClientCannotAuthenticate(clientID string) error {
|
||||
userID, client := s.t.getIMAPClient(clientID)
|
||||
|
||||
if err := client.Login(s.t.getUserByID(userID).getEmails()[0], s.t.getUserByID(userID).getBridgePass()); err == nil {
|
||||
if err := s.loginWithAuthMethod(
|
||||
client,
|
||||
s.t.getUserByID(userID).getEmails()[0],
|
||||
s.t.getUserByID(userID).getBridgePass(),
|
||||
imapLogin,
|
||||
); err == nil {
|
||||
return fmt.Errorf("expected error, got nil")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *scenario) imapClientCannotAuthenticateUsingIMAPAuthenticate(clientID string) error {
|
||||
userID, client := s.t.getIMAPClient(clientID)
|
||||
|
||||
if err := s.loginWithAuthMethod(
|
||||
client,
|
||||
s.t.getUserByID(userID).getEmails()[0],
|
||||
s.t.getUserByID(userID).getBridgePass(),
|
||||
imapAuthenticate,
|
||||
); err == nil {
|
||||
return fmt.Errorf("expected error, got nil")
|
||||
}
|
||||
|
||||
@ -101,7 +171,7 @@ func (s *scenario) imapClientCannotAuthenticate(clientID string) error {
|
||||
func (s *scenario) imapClientCannotAuthenticateWithAddress(clientID, address string) error {
|
||||
userID, client := s.t.getIMAPClient(clientID)
|
||||
|
||||
if err := client.Login(address, s.t.getUserByID(userID).getBridgePass()); err == nil {
|
||||
if err := s.loginWithAuthMethod(client, address, s.t.getUserByID(userID).getBridgePass(), imapLogin); err == nil {
|
||||
return fmt.Errorf("expected error, got nil")
|
||||
}
|
||||
|
||||
@ -111,7 +181,27 @@ func (s *scenario) imapClientCannotAuthenticateWithAddress(clientID, address str
|
||||
func (s *scenario) imapClientCannotAuthenticateWithIncorrectUsername(clientID string) error {
|
||||
userID, client := s.t.getIMAPClient(clientID)
|
||||
|
||||
if err := client.Login(s.t.getUserByID(userID).getEmails()[0]+"bad", s.t.getUserByID(userID).getBridgePass()); err == nil {
|
||||
if err := s.loginWithAuthMethod(
|
||||
client,
|
||||
s.t.getUserByID(userID).getEmails()[0]+"bad",
|
||||
s.t.getUserByID(userID).getBridgePass(),
|
||||
imapLogin,
|
||||
); err == nil {
|
||||
return fmt.Errorf("expected error, got nil")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *scenario) imapClientCannotAuthenticateWithIncorrectUsernameUsingIMAPAuthenticate(clientID string) error {
|
||||
userID, client := s.t.getIMAPClient(clientID)
|
||||
|
||||
if err := s.loginWithAuthMethod(
|
||||
client,
|
||||
s.t.getUserByID(userID).getEmails()[0]+"bad",
|
||||
s.t.getUserByID(userID).getBridgePass(),
|
||||
imapAuthenticate,
|
||||
); err == nil {
|
||||
return fmt.Errorf("expected error, got nil")
|
||||
}
|
||||
|
||||
@ -121,7 +211,17 @@ func (s *scenario) imapClientCannotAuthenticateWithIncorrectUsername(clientID st
|
||||
func (s *scenario) imapClientCannotAuthenticateWithIncorrectPassword(clientID string) error {
|
||||
userID, client := s.t.getIMAPClient(clientID)
|
||||
badPass := base64.StdEncoding.EncodeToString([]byte("bad_password"))
|
||||
if err := client.Login(s.t.getUserByID(userID).getEmails()[0], badPass); err == nil {
|
||||
if err := s.loginWithAuthMethod(client, s.t.getUserByID(userID).getEmails()[0], badPass, imapLogin); err == nil {
|
||||
return fmt.Errorf("expected error, got nil")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *scenario) imapClientCannotAuthenticateWithIncorrectPasswordUsingIMAPAuthenticate(clientID string) error {
|
||||
userID, client := s.t.getIMAPClient(clientID)
|
||||
badPass := base64.StdEncoding.EncodeToString([]byte("bad_password"))
|
||||
if err := s.loginWithAuthMethod(client, s.t.getUserByID(userID).getEmails()[0], badPass, imapAuthenticate); err == nil {
|
||||
return fmt.Errorf("expected error, got nil")
|
||||
}
|
||||
|
||||
|
||||
@ -129,13 +129,19 @@ func (s *scenario) steps(ctx *godog.ScenarioContext) {
|
||||
ctx.Step(`^user "([^"]*)" connects IMAP client "([^"]*)" on port (\d+)$`, s.userConnectsIMAPClientOnPort)
|
||||
ctx.Step(`^user "([^"]*)" connects and authenticates IMAP client "([^"]*)"$`, s.userConnectsAndAuthenticatesIMAPClient)
|
||||
ctx.Step(`^user "([^"]*)" connects and authenticates IMAP client "([^"]*)" with address "([^"]*)"$`, s.userConnectsAndAuthenticatesIMAPClientWithAddress)
|
||||
ctx.Step(`^user "([^"]*)" connects and authenticates IMAP client "([^"]*)" with address "([^"]*)" using IMAP AUTHENTICATE$`, s.userConnectsAndAuthenticatesIMAPClientWithAddressUsingIMAPAuthenticate)
|
||||
ctx.Step(`^user "([^"]*)" connects and can not authenticate IMAP client "([^"]*)" with address "([^"]*)"$`, s.userConnectsAndCanNotAuthenticateIMAPClientWithAddress)
|
||||
ctx.Step(`^IMAP client "([^"]*)" can authenticate$`, s.imapClientCanAuthenticate)
|
||||
ctx.Step(`^IMAP client "([^"]*)" can authenticate using IMAP AUTHENTICATE$`, s.imapClientCanAuthenticateUsingIMAPAuthenticate)
|
||||
ctx.Step(`^IMAP client "([^"]*)" can authenticate with address "([^"]*)"$`, s.imapClientCanAuthenticateWithAddress)
|
||||
ctx.Step(`^IMAP client "([^"]*)" can authenticate with address "([^"]*)" using IMAP AUTHENTICATE$`, s.imapClientCanAuthenticateWithAddressUsingIMAPAuthenticate)
|
||||
ctx.Step(`^IMAP client "([^"]*)" cannot authenticate$`, s.imapClientCannotAuthenticate)
|
||||
ctx.Step(`^IMAP client "([^"]*)" cannot authenticate using IMAP AUTHENTICATE$`, s.imapClientCannotAuthenticateUsingIMAPAuthenticate)
|
||||
ctx.Step(`^IMAP client "([^"]*)" cannot authenticate with address "([^"]*)"$`, s.imapClientCannotAuthenticateWithAddress)
|
||||
ctx.Step(`^IMAP client "([^"]*)" cannot authenticate with incorrect username$`, s.imapClientCannotAuthenticateWithIncorrectUsername)
|
||||
ctx.Step(`^IMAP client "([^"]*)" cannot authenticate with incorrect username using IMAP AUTHENTICATE$`, s.imapClientCannotAuthenticateWithIncorrectUsernameUsingIMAPAuthenticate)
|
||||
ctx.Step(`^IMAP client "([^"]*)" cannot authenticate with incorrect password$`, s.imapClientCannotAuthenticateWithIncorrectPassword)
|
||||
ctx.Step(`^IMAP client "([^"]*)" cannot authenticate with incorrect password using IMAP AUTHENTICATE$`, s.imapClientCannotAuthenticateWithIncorrectPasswordUsingIMAPAuthenticate)
|
||||
ctx.Step(`^IMAP client "([^"]*)" closes$`, s.imapClientCloses)
|
||||
ctx.Step(`^IMAP client "([^"]*)" announces its ID with name "([^"]*)" and version "([^"]*)"$`, s.imapClientAnnouncesItsIDWithNameAndVersion)
|
||||
ctx.Step(`^IMAP client "([^"]*)" creates "([^"]*)"$`, s.imapClientCreatesMailbox)
|
||||
|
||||
Reference in New Issue
Block a user