GODT-2305: Detect missing gluon DB

This commit is contained in:
James Houlahan 2023-01-25 14:48:30 +01:00
parent e7dea0a77f
commit cf32b84257
4 changed files with 26 additions and 43 deletions

2
go.mod
View File

@ -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

4
go.sum
View File

@ -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=

View File

@ -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) {

View File

@ -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")