mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-15 22:56:48 +00:00
feat(GODT-2940): allow 3 attempts for mailbox password.
This commit is contained in:
@ -46,6 +46,8 @@ const (
|
|||||||
Connected
|
Connected
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var ErrFailedToUnlock = errors.New("failed to unlock user keys")
|
||||||
|
|
||||||
type UserInfo struct {
|
type UserInfo struct {
|
||||||
// UserID is the user's API ID.
|
// UserID is the user's API ID.
|
||||||
UserID string
|
UserID string
|
||||||
@ -157,11 +159,15 @@ func (bridge *Bridge) LoginUser(
|
|||||||
func() (string, error) {
|
func() (string, error) {
|
||||||
return bridge.loginUser(ctx, client, auth.UID, auth.RefreshToken, keyPass)
|
return bridge.loginUser(ctx, client, auth.UID, auth.RefreshToken, keyPass)
|
||||||
},
|
},
|
||||||
func() error {
|
|
||||||
return client.AuthDelete(ctx)
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// Failure to unlock will allow retries, so we do not delete auth.
|
||||||
|
if !errors.Is(err, ErrFailedToUnlock) {
|
||||||
|
if deleteErr := client.AuthDelete(ctx); deleteErr != nil {
|
||||||
|
logrus.WithError(deleteErr).Error("Failed to delete auth")
|
||||||
|
}
|
||||||
|
}
|
||||||
return "", fmt.Errorf("failed to login user: %w", err)
|
return "", fmt.Errorf("failed to login user: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,7 +223,16 @@ func (bridge *Bridge) LoginFull(
|
|||||||
keyPass = password
|
keyPass = password
|
||||||
}
|
}
|
||||||
|
|
||||||
return bridge.LoginUser(ctx, client, auth, keyPass)
|
userID, err := bridge.LoginUser(ctx, client, auth, keyPass)
|
||||||
|
if err != nil {
|
||||||
|
if deleteErr := client.AuthDelete(ctx); deleteErr != nil {
|
||||||
|
logrus.WithError(err).Error("Failed to delete auth")
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return userID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LogoutUser logs out the given user.
|
// LogoutUser logs out the given user.
|
||||||
@ -374,9 +389,9 @@ func (bridge *Bridge) loginUser(ctx context.Context, client *proton.Client, auth
|
|||||||
}
|
}
|
||||||
|
|
||||||
if userKR, err := apiUser.Keys.Unlock(saltedKeyPass, nil); err != nil {
|
if userKR, err := apiUser.Keys.Unlock(saltedKeyPass, nil); err != nil {
|
||||||
return "", fmt.Errorf("failed to unlock user keys: %w", err)
|
return "", fmt.Errorf("%w: %w", ErrFailedToUnlock, err)
|
||||||
} else if userKR.CountDecryptionEntities() == 0 {
|
} else if userKR.CountDecryptionEntities() == 0 {
|
||||||
return "", fmt.Errorf("failed to unlock user keys")
|
return "", ErrFailedToUnlock
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := bridge.addUser(ctx, client, apiUser, authUID, authRef, saltedKeyPass, true); err != nil {
|
if err := bridge.addUser(ctx, client, apiUser, authUID, authRef, saltedKeyPass, true); err != nil {
|
||||||
|
|||||||
@ -56,6 +56,7 @@ import (
|
|||||||
const (
|
const (
|
||||||
serverConfigFileName = "grpcServerConfig.json"
|
serverConfigFileName = "grpcServerConfig.json"
|
||||||
serverTokenMetadataKey = "server-token"
|
serverTokenMetadataKey = "server-token"
|
||||||
|
twoPasswordsMaxAttemptCount = 3 // The number of attempts allowed for the mailbox password.
|
||||||
)
|
)
|
||||||
|
|
||||||
// Service is the RPC service struct.
|
// Service is the RPC service struct.
|
||||||
@ -85,6 +86,7 @@ type Service struct { // nolint:structcheck
|
|||||||
authClient *proton.Client
|
authClient *proton.Client
|
||||||
auth proton.Auth
|
auth proton.Auth
|
||||||
password []byte
|
password []byte
|
||||||
|
twoPasswordAttemptCount int
|
||||||
|
|
||||||
log *logrus.Entry
|
log *logrus.Entry
|
||||||
initializing sync.WaitGroup
|
initializing sync.WaitGroup
|
||||||
@ -408,7 +410,12 @@ func (s *Service) loginClean() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) finishLogin() {
|
func (s *Service) finishLogin() {
|
||||||
defer s.loginClean()
|
performCleanup := true
|
||||||
|
defer func() {
|
||||||
|
if performCleanup {
|
||||||
|
s.loginClean()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
wasSignedOut := s.bridge.HasUser(s.auth.UserID)
|
wasSignedOut := s.bridge.HasUser(s.auth.UserID)
|
||||||
|
|
||||||
@ -426,10 +433,24 @@ func (s *Service) finishLogin() {
|
|||||||
eventCh, done := s.bridge.GetEvents(events.UserLoggedIn{})
|
eventCh, done := s.bridge.GetEvents(events.UserLoggedIn{})
|
||||||
defer done()
|
defer done()
|
||||||
|
|
||||||
userID, err := s.bridge.LoginUser(context.Background(), s.authClient, s.auth, s.password)
|
ctx := context.Background()
|
||||||
|
userID, err := s.bridge.LoginUser(ctx, s.authClient, s.auth, s.password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.WithError(err).Errorf("Finish login failed")
|
s.log.WithError(err).Errorf("Finish login failed")
|
||||||
_ = s.SendEvent(NewLoginError(LoginErrorType_TWO_PASSWORDS_ABORT, err.Error()))
|
s.twoPasswordAttemptCount++
|
||||||
|
errType := LoginErrorType_TWO_PASSWORDS_ABORT
|
||||||
|
if errors.Is(err, bridge.ErrFailedToUnlock) {
|
||||||
|
if s.twoPasswordAttemptCount < twoPasswordsMaxAttemptCount {
|
||||||
|
performCleanup = false
|
||||||
|
errType = LoginErrorType_TWO_PASSWORDS_ERROR
|
||||||
|
} else {
|
||||||
|
if deleteErr := s.authClient.AuthDelete(ctx); deleteErr != nil {
|
||||||
|
s.log.WithError(deleteErr).Error("Failed to delete auth")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = s.SendEvent(NewLoginError(errType, err.Error()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -384,6 +384,7 @@ func (s *Service) Login(_ context.Context, login *LoginRequest) (*emptypb.Empty,
|
|||||||
go func() {
|
go func() {
|
||||||
defer async.HandlePanic(s.panicHandler)
|
defer async.HandlePanic(s.panicHandler)
|
||||||
|
|
||||||
|
s.twoPasswordAttemptCount = 0
|
||||||
password, err := base64Decode(login.Password)
|
password, err := base64Decode(login.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.log.WithError(err).Error("Cannot decode password")
|
s.log.WithError(err).Error("Cannot decode password")
|
||||||
|
|||||||
Reference in New Issue
Block a user