mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-10 20:56:51 +00:00
Close connection before deleting labels to prevent panics accessing deleted bucket
This commit is contained in:
committed by
Jakub Cuth
parent
f0695eb870
commit
b9740e1b7d
@ -15,6 +15,7 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/)
|
|||||||
* GODT-849 Show in error counts in the end also lost messages.
|
* GODT-849 Show in error counts in the end also lost messages.
|
||||||
* GODT-835 Do not include conversation ID in references to show properly conversation threads in clients.
|
* GODT-835 Do not include conversation ID in references to show properly conversation threads in clients.
|
||||||
* GODT-799 Fix skipping unwanted folders importing from mbox files.
|
* GODT-799 Fix skipping unwanted folders importing from mbox files.
|
||||||
|
* GODT-769 Close connection before deleting labels to prevent panics accessing deleted bucket.
|
||||||
|
|
||||||
## [IE 1.2.0] Elbe
|
## [IE 1.2.0] Elbe
|
||||||
|
|
||||||
|
|||||||
@ -38,6 +38,8 @@ type Mailbox struct {
|
|||||||
color string
|
color string
|
||||||
|
|
||||||
log *logrus.Entry
|
log *logrus.Entry
|
||||||
|
|
||||||
|
isDeleting bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMailbox(storeAddress *Address, labelID, labelPrefix, labelName, color string) (mb *Mailbox, err error) {
|
func newMailbox(storeAddress *Address, labelID, labelPrefix, labelName, color string) (mb *Mailbox, err error) {
|
||||||
@ -215,6 +217,7 @@ func (storeMailbox *Mailbox) Rename(newName string) error {
|
|||||||
// Deletion has to be propagated to all the same mailboxes in all addresses.
|
// Deletion has to be propagated to all the same mailboxes in all addresses.
|
||||||
// The propagation is processed by the event loop.
|
// The propagation is processed by the event loop.
|
||||||
func (storeMailbox *Mailbox) Delete() error {
|
func (storeMailbox *Mailbox) Delete() error {
|
||||||
|
storeMailbox.isDeleting = true
|
||||||
return storeMailbox.storeAddress.deleteMailbox(storeMailbox.labelID)
|
return storeMailbox.storeAddress.deleteMailbox(storeMailbox.labelID)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,6 +229,14 @@ func (storeMailbox *Mailbox) GetDelimiter() string {
|
|||||||
// deleteMailboxEvent deletes the mailbox bucket.
|
// deleteMailboxEvent deletes the mailbox bucket.
|
||||||
// This is called from the event loop.
|
// This is called from the event loop.
|
||||||
func (storeMailbox *Mailbox) deleteMailboxEvent() error {
|
func (storeMailbox *Mailbox) deleteMailboxEvent() error {
|
||||||
|
if !storeMailbox.isDeleting {
|
||||||
|
// Deleting label removes bucket. Any ongoing connection selected
|
||||||
|
// in such mailbox then might panic because of non-existing bucket.
|
||||||
|
// Closing connetions prevents that panic but if the connection
|
||||||
|
// asked for deletion, it should not be closed so it can receive
|
||||||
|
// successful response.
|
||||||
|
storeMailbox.store.user.CloseAllConnections()
|
||||||
|
}
|
||||||
return storeMailbox.db().Update(func(tx *bolt.Tx) error {
|
return storeMailbox.db().Update(func(tx *bolt.Tx) error {
|
||||||
return tx.Bucket(mailboxesBucket).DeleteBucket(storeMailbox.getBucketName())
|
return tx.Bucket(mailboxesBucket).DeleteBucket(storeMailbox.getBucketName())
|
||||||
})
|
})
|
||||||
|
|||||||
@ -106,6 +106,18 @@ func (m *MockBridgeUser) EXPECT() *MockBridgeUserMockRecorder {
|
|||||||
return m.recorder
|
return m.recorder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CloseAllConnections mocks base method
|
||||||
|
func (m *MockBridgeUser) CloseAllConnections() {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
m.ctrl.Call(m, "CloseAllConnections")
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloseAllConnections indicates an expected call of CloseAllConnections
|
||||||
|
func (mr *MockBridgeUserMockRecorder) CloseAllConnections() *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloseAllConnections", reflect.TypeOf((*MockBridgeUser)(nil).CloseAllConnections))
|
||||||
|
}
|
||||||
|
|
||||||
// CloseConnection mocks base method
|
// CloseConnection mocks base method
|
||||||
func (m *MockBridgeUser) CloseConnection(arg0 string) {
|
func (m *MockBridgeUser) CloseConnection(arg0 string) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
|||||||
@ -36,6 +36,7 @@ type BridgeUser interface {
|
|||||||
GetPrimaryAddress() string
|
GetPrimaryAddress() string
|
||||||
GetStoreAddresses() []string
|
GetStoreAddresses() []string
|
||||||
UpdateUser() error
|
UpdateUser() error
|
||||||
|
CloseAllConnections()
|
||||||
CloseConnection(string)
|
CloseConnection(string)
|
||||||
Logout() error
|
Logout() error
|
||||||
}
|
}
|
||||||
|
|||||||
@ -437,7 +437,7 @@ func (u *User) SwitchAddressMode() (err error) {
|
|||||||
|
|
||||||
u.lock.Lock()
|
u.lock.Lock()
|
||||||
defer u.lock.Unlock()
|
defer u.lock.Unlock()
|
||||||
u.closeAllConnections()
|
u.CloseAllConnections()
|
||||||
|
|
||||||
if u.store == nil {
|
if u.store == nil {
|
||||||
err = errors.New("store is not initialised")
|
err = errors.New("store is not initialised")
|
||||||
@ -509,7 +509,7 @@ func (u *User) Logout() (err error) {
|
|||||||
// Do not close whole store, just event loop. Some information might be needed offline (e.g. addressID)
|
// Do not close whole store, just event loop. Some information might be needed offline (e.g. addressID)
|
||||||
u.closeEventLoop()
|
u.closeEventLoop()
|
||||||
|
|
||||||
u.closeAllConnections()
|
u.CloseAllConnections()
|
||||||
|
|
||||||
runtime.GC()
|
runtime.GC()
|
||||||
|
|
||||||
@ -532,8 +532,8 @@ func (u *User) closeEventLoop() {
|
|||||||
u.store.CloseEventLoop()
|
u.store.CloseEventLoop()
|
||||||
}
|
}
|
||||||
|
|
||||||
// closeAllConnections calls CloseConnection for all users addresses.
|
// CloseAllConnections calls CloseConnection for all users addresses.
|
||||||
func (u *User) closeAllConnections() {
|
func (u *User) CloseAllConnections() {
|
||||||
for _, address := range u.creds.EmailList() {
|
for _, address := range u.creds.EmailList() {
|
||||||
u.CloseConnection(address)
|
u.CloseConnection(address)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -186,7 +186,7 @@ func (u *Users) watchAPIAuths() {
|
|||||||
|
|
||||||
func (u *Users) closeAllConnections() {
|
func (u *Users) closeAllConnections() {
|
||||||
for _, user := range u.users {
|
for _, user := range u.users {
|
||||||
user.closeAllConnections()
|
user.CloseAllConnections()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,12 +5,11 @@
|
|||||||
package mocks
|
package mocks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
io "io"
|
|
||||||
reflect "reflect"
|
|
||||||
|
|
||||||
crypto "github.com/ProtonMail/gopenpgp/v2/crypto"
|
crypto "github.com/ProtonMail/gopenpgp/v2/crypto"
|
||||||
pmapi "github.com/ProtonMail/proton-bridge/pkg/pmapi"
|
pmapi "github.com/ProtonMail/proton-bridge/pkg/pmapi"
|
||||||
gomock "github.com/golang/mock/gomock"
|
gomock "github.com/golang/mock/gomock"
|
||||||
|
io "io"
|
||||||
|
reflect "reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MockClient is a mock of Client interface
|
// MockClient is a mock of Client interface
|
||||||
|
|||||||
Reference in New Issue
Block a user