mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-22 01:56:44 +00:00
Other(refactor): Sort safe.Mutex types before locking to prevent deadlocks
This change implements safe.Mutex and safe.RWMutex, which wrap the sync.Mutex and sync.RWMutex types and are assigned a globally unique integer ID. The safe.Lock and safe.RLock methods sort the mutexes by this integer ID before locking to ensure that locks for a given set of mutexes are always performed in the same order, avoiding deadlocks.
This commit is contained in:
@ -52,7 +52,7 @@ type Bridge struct {
|
||||
|
||||
// users holds authorized users.
|
||||
users map[string]*user.User
|
||||
usersLock sync.RWMutex
|
||||
usersLock safe.RWMutex
|
||||
|
||||
// api manages user API clients.
|
||||
api *liteapi.Manager
|
||||
@ -226,7 +226,9 @@ func newBridge(
|
||||
|
||||
bridge := &Bridge{
|
||||
vault: vault,
|
||||
users: make(map[string]*user.User),
|
||||
|
||||
users: make(map[string]*user.User),
|
||||
usersLock: safe.NewRWMutex(),
|
||||
|
||||
api: api,
|
||||
proxyCtl: proxyCtl,
|
||||
@ -363,7 +365,7 @@ func (bridge *Bridge) Close(ctx context.Context) {
|
||||
for _, user := range bridge.users {
|
||||
user.Close()
|
||||
}
|
||||
}, &bridge.usersLock)
|
||||
}, bridge.usersLock)
|
||||
|
||||
// Stop all ongoing tasks.
|
||||
bridge.tasks.Wait()
|
||||
@ -433,7 +435,7 @@ func (bridge *Bridge) onStatusUp() {
|
||||
for _, user := range bridge.users {
|
||||
user.OnStatusUp()
|
||||
}
|
||||
}, &bridge.usersLock)
|
||||
}, bridge.usersLock)
|
||||
|
||||
bridge.goLoad()
|
||||
}
|
||||
@ -445,7 +447,7 @@ func (bridge *Bridge) onStatusDown() {
|
||||
for _, user := range bridge.users {
|
||||
user.OnStatusDown()
|
||||
}
|
||||
}, &bridge.usersLock)
|
||||
}, bridge.usersLock)
|
||||
|
||||
bridge.tasks.Once(func(ctx context.Context) {
|
||||
backoff := time.Second
|
||||
|
||||
@ -64,5 +64,5 @@ func (bridge *Bridge) ConfigureAppleMail(userID, address string) error {
|
||||
addresses,
|
||||
user.BridgePass(),
|
||||
)
|
||||
}, &bridge.usersLock)
|
||||
}, bridge.usersLock)
|
||||
}
|
||||
|
||||
@ -161,7 +161,7 @@ func (bridge *Bridge) SetGluonDir(ctx context.Context, newGluonDir string) error
|
||||
}
|
||||
|
||||
return nil
|
||||
}, &bridge.usersLock)
|
||||
}, bridge.usersLock)
|
||||
}
|
||||
|
||||
func (bridge *Bridge) GetProxyAllowed() bool {
|
||||
@ -189,7 +189,7 @@ func (bridge *Bridge) SetShowAllMail(show bool) error {
|
||||
}
|
||||
|
||||
return bridge.vault.SetShowAllMail(show)
|
||||
}, &bridge.usersLock)
|
||||
}, bridge.usersLock)
|
||||
}
|
||||
|
||||
func (bridge *Bridge) GetAutostart() bool {
|
||||
@ -288,7 +288,7 @@ func (bridge *Bridge) FactoryReset(ctx context.Context) {
|
||||
logrus.WithError(err).Error("failed to delete vault user")
|
||||
}
|
||||
}
|
||||
}, &bridge.usersLock)
|
||||
}, bridge.usersLock)
|
||||
|
||||
// Then delete all files.
|
||||
if err := bridge.locator.Clear(); err != nil {
|
||||
|
||||
@ -58,7 +58,7 @@ func (s *smtpSession) AuthPlain(username, password string) error {
|
||||
}
|
||||
|
||||
return fmt.Errorf("invalid username or password")
|
||||
}, &s.usersLock)
|
||||
}, s.usersLock)
|
||||
}
|
||||
|
||||
func (s *smtpSession) Reset() {
|
||||
@ -92,5 +92,5 @@ func (s *smtpSession) Data(r io.Reader) error {
|
||||
}
|
||||
|
||||
return user.SendMail(s.authID, s.from, s.to, r)
|
||||
}, &s.usersLock)
|
||||
}, s.usersLock)
|
||||
}
|
||||
|
||||
@ -80,7 +80,7 @@ func (bridge *Bridge) GetUserInfo(userID string) (UserInfo, error) {
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}, &bridge.usersLock)
|
||||
}, bridge.usersLock)
|
||||
}
|
||||
|
||||
// QueryUserInfo queries the user info by username or address.
|
||||
@ -93,7 +93,7 @@ func (bridge *Bridge) QueryUserInfo(query string) (UserInfo, error) {
|
||||
}
|
||||
|
||||
return UserInfo{}, ErrNoSuchUser
|
||||
}, &bridge.usersLock)
|
||||
}, bridge.usersLock)
|
||||
}
|
||||
|
||||
// LoginAuth begins the login process. It returns an authorized client that might need 2FA.
|
||||
@ -105,7 +105,7 @@ func (bridge *Bridge) LoginAuth(ctx context.Context, username string, password [
|
||||
|
||||
if ok := safe.RLockRet(func() bool {
|
||||
return mapHas(bridge.users, auth.UID)
|
||||
}, &bridge.usersLock); ok {
|
||||
}, bridge.usersLock); ok {
|
||||
if err := client.AuthDelete(ctx); err != nil {
|
||||
logrus.WithError(err).Warn("Failed to delete auth")
|
||||
}
|
||||
@ -201,7 +201,7 @@ func (bridge *Bridge) LogoutUser(ctx context.Context, userID string) error {
|
||||
})
|
||||
|
||||
return nil
|
||||
}, &bridge.usersLock)
|
||||
}, bridge.usersLock)
|
||||
}
|
||||
|
||||
// DeleteUser deletes the given user.
|
||||
@ -225,7 +225,7 @@ func (bridge *Bridge) DeleteUser(ctx context.Context, userID string) error {
|
||||
})
|
||||
|
||||
return nil
|
||||
}, &bridge.usersLock)
|
||||
}, bridge.usersLock)
|
||||
}
|
||||
|
||||
// SetAddressMode sets the address mode for the given user.
|
||||
@ -260,7 +260,7 @@ func (bridge *Bridge) SetAddressMode(ctx context.Context, userID string, mode va
|
||||
})
|
||||
|
||||
return nil
|
||||
}, &bridge.usersLock)
|
||||
}, bridge.usersLock)
|
||||
}
|
||||
|
||||
func (bridge *Bridge) loginUser(ctx context.Context, client *liteapi.Client, authUID, authRef string, keyPass []byte) (string, error) {
|
||||
@ -295,7 +295,7 @@ func (bridge *Bridge) loadUsers(ctx context.Context) error {
|
||||
|
||||
if safe.RLockRet(func() bool {
|
||||
return mapHas(bridge.users, user.UserID())
|
||||
}, &bridge.usersLock) {
|
||||
}, bridge.usersLock) {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -419,7 +419,7 @@ func (bridge *Bridge) addUserWithVault(
|
||||
// Finally, save the user in the bridge.
|
||||
safe.Lock(func() {
|
||||
bridge.users[apiUser.ID] = user
|
||||
}, &bridge.usersLock)
|
||||
}, bridge.usersLock)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@ func (bridge *Bridge) handleUserEvent(ctx context.Context, user *user.User, even
|
||||
defer delete(bridge.users, user.ID())
|
||||
|
||||
bridge.logoutUser(ctx, user, false)
|
||||
}, &bridge.usersLock)
|
||||
}, bridge.usersLock)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user