GODT-1515: Do not crash when bridge users got disconnected.

This commit is contained in:
Jakub
2022-02-22 16:41:32 +01:00
parent aa8cc3fc4b
commit 63379001e3
5 changed files with 50 additions and 1 deletions

View File

@ -345,6 +345,10 @@ func (u *User) GetAddressID(address string) (id string, err error) {
return u.store.GetAddressID(address) return u.store.GetAddressID(address)
} }
if u.client == nil {
return "", errors.New("bridge account is not fully connected to server")
}
addresses := u.client.Addresses() addresses := u.client.Addresses()
pmapiAddress := addresses.ByEmail(address) pmapiAddress := addresses.ByEmail(address)
if pmapiAddress != nil { if pmapiAddress != nil {
@ -473,7 +477,9 @@ func (u *User) Logout() error {
return nil return nil
} }
if err := u.client.AuthDelete(context.Background()); err != nil { if u.client == nil {
u.log.Warn("Failed to delete auth: no client")
} else if err := u.client.AuthDelete(context.Background()); err != nil {
u.log.WithError(err).Warn("Failed to delete auth") u.log.WithError(err).Warn("Failed to delete auth")
} }

View File

@ -172,3 +172,7 @@ func (ctx *TestContext) MessagePreparationStarted(username string) {
func (ctx *TestContext) MessagePreparationFinished(username string) { func (ctx *TestContext) MessagePreparationFinished(username string) {
ctx.pmapiController.UnlockEvents(username) ctx.pmapiController.UnlockEvents(username)
} }
func (ctx *TestContext) CredentialsFailsOnWrite(shouldFail bool) {
ctx.credStore.(*fakeCredStore).failOnWrite = shouldFail
}

View File

@ -21,6 +21,7 @@ import (
"strings" "strings"
"github.com/ProtonMail/proton-bridge/internal/users/credentials" "github.com/ProtonMail/proton-bridge/internal/users/credentials"
"github.com/pkg/errors"
) )
// bridgePassword is password to be used for IMAP or SMTP under tests. // bridgePassword is password to be used for IMAP or SMTP under tests.
@ -28,6 +29,8 @@ const bridgePassword = "bridgepassword"
type fakeCredStore struct { type fakeCredStore struct {
credentials map[string]*credentials.Credentials credentials map[string]*credentials.Credentials
failOnWrite bool
} }
// newFakeCredStore returns a fake credentials store (optionally configured with the given credentials). // newFakeCredStore returns a fake credentials store (optionally configured with the given credentials).
@ -52,6 +55,9 @@ func (c *fakeCredStore) List() (userIDs []string, err error) {
} }
func (c *fakeCredStore) Add(userID, userName, uid, ref string, mailboxPassword []byte, emails []string) (*credentials.Credentials, error) { func (c *fakeCredStore) Add(userID, userName, uid, ref string, mailboxPassword []byte, emails []string) (*credentials.Credentials, error) {
if c.failOnWrite {
return nil, errors.New("An invalid attempt to change the owner of an item. (-25244)")
}
bridgePassword := bridgePassword bridgePassword := bridgePassword
if c, ok := c.credentials[userID]; ok { if c, ok := c.credentials[userID]; ok {
bridgePassword = c.BridgePassword bridgePassword = c.BridgePassword
@ -73,14 +79,23 @@ func (c *fakeCredStore) Get(userID string) (*credentials.Credentials, error) {
} }
func (c *fakeCredStore) SwitchAddressMode(userID string) (*credentials.Credentials, error) { func (c *fakeCredStore) SwitchAddressMode(userID string) (*credentials.Credentials, error) {
if c.failOnWrite {
return nil, errors.New("An invalid attempt to change the owner of an item. (-25244)")
}
return c.credentials[userID], nil return c.credentials[userID], nil
} }
func (c *fakeCredStore) UpdateEmails(userID string, emails []string) (*credentials.Credentials, error) { func (c *fakeCredStore) UpdateEmails(userID string, emails []string) (*credentials.Credentials, error) {
if c.failOnWrite {
return nil, errors.New("An invalid attempt to change the owner of an item. (-25244)")
}
return c.credentials[userID], nil return c.credentials[userID], nil
} }
func (c *fakeCredStore) UpdatePassword(userID string, password []byte) (*credentials.Credentials, error) { func (c *fakeCredStore) UpdatePassword(userID string, password []byte) (*credentials.Credentials, error) {
if c.failOnWrite {
return nil, errors.New("An invalid attempt to change the owner of an item. (-25244)")
}
creds, err := c.Get(userID) creds, err := c.Get(userID)
if err != nil { if err != nil {
return nil, err return nil, err
@ -90,6 +105,9 @@ func (c *fakeCredStore) UpdatePassword(userID string, password []byte) (*credent
} }
func (c *fakeCredStore) UpdateToken(userID, uid, ref string) (*credentials.Credentials, error) { func (c *fakeCredStore) UpdateToken(userID, uid, ref string) (*credentials.Credentials, error) {
if c.failOnWrite {
return nil, errors.New("An invalid attempt to change the owner of an item. (-25244)")
}
creds, err := c.Get(userID) creds, err := c.Get(userID)
if err != nil { if err != nil {
return nil, err return nil, err
@ -99,12 +117,18 @@ func (c *fakeCredStore) UpdateToken(userID, uid, ref string) (*credentials.Crede
} }
func (c *fakeCredStore) Logout(userID string) (*credentials.Credentials, error) { func (c *fakeCredStore) Logout(userID string) (*credentials.Credentials, error) {
if c.failOnWrite {
return nil, errors.New("An invalid attempt to change the owner of an item. (-25244)")
}
c.credentials[userID].APIToken = "" c.credentials[userID].APIToken = ""
c.credentials[userID].MailboxPassword = []byte{} c.credentials[userID].MailboxPassword = []byte{}
return c.credentials[userID], nil return c.credentials[userID], nil
} }
func (c *fakeCredStore) Delete(userID string) error { func (c *fakeCredStore) Delete(userID string) error {
if c.failOnWrite {
return errors.New("An invalid attempt to change the owner of an item. (-25244)")
}
delete(c.credentials, userID) delete(c.credentials, userID)
return nil return nil
} }

View File

@ -79,3 +79,12 @@ Feature: Start bridge
And "user" does not have loaded store And "user" does not have loaded store
And "user" does not have running event loop And "user" does not have running event loop
And "user" has zero space And "user" has zero space
Scenario: Start with connected user, database file and internet connection, but no write access to credentials
Given there is user "user" which just logged in
And credentials are locked
And there is database file for "user"
When bridge starts
Then "user" is connected
When IMAP client authenticates "user"
Then IMAP response is "NO"

View File

@ -33,6 +33,7 @@ func UsersSetupFeatureContext(s *godog.ScenarioContext) {
s.Step(`^there is database file for "([^"]*)"$`, thereIsDatabaseFileForUser) s.Step(`^there is database file for "([^"]*)"$`, thereIsDatabaseFileForUser)
s.Step(`^there is no database file for "([^"]*)"$`, thereIsNoDatabaseFileForUser) s.Step(`^there is no database file for "([^"]*)"$`, thereIsNoDatabaseFileForUser)
s.Step(`^there is "([^"]*)" in "([^"]*)" address mode$`, thereIsUserWithAddressMode) s.Step(`^there is "([^"]*)" in "([^"]*)" address mode$`, thereIsUserWithAddressMode)
s.Step(`^credentials? (?:are|is) locked$`, credentialsAreLocked)
} }
func thereIsUser(bddUserID string) error { func thereIsUser(bddUserID string) error {
@ -150,3 +151,8 @@ func thereIsUserWithAddressMode(bddUserID, wantAddressMode string) error {
ctx.EventuallySyncIsFinishedForUsername(user.Username()) ctx.EventuallySyncIsFinishedForUsername(user.Username())
return nil return nil
} }
func credentialsAreLocked() error {
ctx.CredentialsFailsOnWrite(true)
return nil
}