diff --git a/go.mod b/go.mod index 44b7c586..96ecd724 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/0xAX/notificator v0.0.0-20220220101646-ee9b8921e557 github.com/Masterminds/semver/v3 v3.1.1 - github.com/ProtonMail/gluon v0.14.2-0.20230123154940-b7793a0c0bd4 + github.com/ProtonMail/gluon v0.14.2-0.20230125124704-4ce9fef3fdb3 github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a github.com/ProtonMail/go-proton-api v0.3.1-0.20230125082844-35702fd064a5 github.com/ProtonMail/go-rfc5322 v0.11.0 diff --git a/go.sum b/go.sum index 876f5a32..4b29ee0c 100644 --- a/go.sum +++ b/go.sum @@ -28,8 +28,8 @@ github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf h1:yc9daCCYUefEs github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf/go.mod h1:o0ESU9p83twszAU8LBeJKFAAMX14tISa0yk4Oo5TOqo= github.com/ProtonMail/docker-credential-helpers v1.1.0 h1:+kvUIpwWcbtP3WFv5sSvkFn/XLzSqPOB5AAthuk9xPk= github.com/ProtonMail/docker-credential-helpers v1.1.0/go.mod h1:mK0aBveCxhnQ756AmaTfXMZDeULvheYVhF/MWMErN5g= -github.com/ProtonMail/gluon v0.14.2-0.20230123154940-b7793a0c0bd4 h1:AkRcjX1iArf8fVL4vZd6eaBjE3+SFnwZQKsH3OMyExU= -github.com/ProtonMail/gluon v0.14.2-0.20230123154940-b7793a0c0bd4/go.mod h1:z2AxLIiBCT1K+0OBHyaDI7AEaO5qI6/BEC2TE42vs4Q= +github.com/ProtonMail/gluon v0.14.2-0.20230125124704-4ce9fef3fdb3 h1:joOTpar+ITs4RDSOvkICZhLXDDrBPfnjstf/03XtpJk= +github.com/ProtonMail/gluon v0.14.2-0.20230125124704-4ce9fef3fdb3/go.mod h1:z2AxLIiBCT1K+0OBHyaDI7AEaO5qI6/BEC2TE42vs4Q= 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-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= diff --git a/internal/bridge/imap.go b/internal/bridge/imap.go index 8380cfe0..928f852f 100644 --- a/internal/bridge/imap.go +++ b/internal/bridge/imap.go @@ -20,13 +20,10 @@ package bridge import ( "context" "crypto/tls" - "errors" "fmt" "io" - "io/fs" "os" "path/filepath" - "runtime" "github.com/Masterminds/semver/v3" "github.com/ProtonMail/gluon" @@ -122,9 +119,20 @@ func (bridge *Bridge) addIMAPUser(ctx context.Context, user *user.User) error { if gluonID, ok := user.GetGluonID(addrID); ok { log.WithField("gluonID", gluonID).Info("Loading existing IMAP user") - if err := bridge.imapServer.LoadUser(ctx, imapConn, gluonID, user.GluonKey()); err != nil { + // Load the user, checking whether the DB was newly created. + isNew, err := bridge.imapServer.LoadUser(ctx, imapConn, gluonID, user.GluonKey()) + if err != nil { return fmt.Errorf("failed to load IMAP user: %w", err) } + + // If the DB was newly created, clear the sync status; gluon's DB was not found. + if isNew { + logrus.Warn("IMAP user DB was newly created, clearing sync status") + + if err := user.ClearSyncStatus(); err != nil { + return fmt.Errorf("failed to clear sync status: %w", err) + } + } } else { log.Info("Creating new IMAP user") @@ -149,6 +157,7 @@ func (bridge *Bridge) removeIMAPUser(ctx context.Context, user *user.User, withD if bridge.imapServer == nil { return fmt.Errorf("no imap server instance running") } + logrus.WithFields(logrus.Fields{ "userID": user.ID(), "withData": withData, @@ -199,23 +208,8 @@ func (bridge *Bridge) handleIMAPEvent(event imapEvents.Event) { } func getGluonDir(encVault *vault.Vault) (string, error) { - empty, exists, err := isEmpty(encVault.GetGluonCacheDir()) - if err != nil { - return "", fmt.Errorf("failed to check if gluon dir is empty: %w", err) - } - - if !exists { - if err := os.MkdirAll(encVault.GetGluonCacheDir(), 0o700); err != nil { - return "", fmt.Errorf("failed to create gluon dir: %w", err) - } - } - - if empty { - if err := encVault.ForUser(runtime.NumCPU(), func(user *vault.User) error { - return user.ClearSyncStatus() - }); err != nil { - return "", fmt.Errorf("failed to reset user sync status: %w", err) - } + if err := os.MkdirAll(encVault.GetGluonCacheDir(), 0o700); err != nil { + return "", fmt.Errorf("failed to create gluon dir: %w", err) } return encVault.GetGluonCacheDir(), nil @@ -310,25 +304,6 @@ func getGluonVersionInfo(version *semver.Version) gluon.Option { ) } -// isEmpty returns whether the given directory is empty. -// If the directory does not exist, the second return value is false. -func isEmpty(dir string) (bool, bool, error) { - if _, err := os.Stat(dir); err != nil { - if !errors.Is(err, fs.ErrNotExist) { - return false, false, fmt.Errorf("failed to stat %s: %w", dir, err) - } - - return true, false, nil - } - - entries, err := os.ReadDir(dir) - if err != nil { - return false, false, fmt.Errorf("failed to read dir %s: %w", dir, err) - } - - return len(entries) == 0, true, nil -} - type storeBuilder struct{} func (*storeBuilder) New(path, userID string, passphrase []byte) (store.Store, error) { diff --git a/internal/user/user.go b/internal/user/user.go index 4abd6d8c..2c48c97d 100644 --- a/internal/user/user.go +++ b/internal/user/user.go @@ -475,6 +475,14 @@ func (user *User) OnStatusDown(context.Context) { user.abortable.Abort() } +// ClearSyncStatus clears the sync status of the user. This triggers a resync. +func (user *User) ClearSyncStatus() error { + user.abortable.Abort() + defer user.goSync() + + return user.vault.ClearSyncStatus() +} + // Logout logs the user out from the API. func (user *User) Logout(ctx context.Context, withAPI bool) error { user.log.WithField("withAPI", withAPI).Info("Logging out user")