When removing an account, wait for the last account reference has gone away before removing the files.

The intent to remove the account is stored in the database. At startup, if
there are any such referenes, they are applied by removing the account
directories and the entry in the database. This ensures the account directory
is properly removed, even on incomplete shutdown.

Don't add an account when its directory already exits.
This commit is contained in:
Mechiel Lukkien
2025-03-15 12:22:04 +01:00
parent c4255a96f8
commit ac4b006ecd
7 changed files with 209 additions and 41 deletions

View File

@ -17,9 +17,15 @@ import (
"github.com/mjl-/mox/moxvar"
)
// AccountRemove represents the scheduled removal of an account, when its last
// reference goes away.
type AccountRemove struct {
AccountName string
}
// AuthDB and AuthDBTypes are exported for ../backup.go.
var AuthDB *bstore.DB
var AuthDBTypes = []any{TLSPublicKey{}, LoginAttempt{}, LoginAttemptState{}}
var AuthDBTypes = []any{TLSPublicKey{}, LoginAttempt{}, LoginAttemptState{}, AccountRemove{}}
var loginAttemptCleanerStop chan chan struct{}
@ -38,6 +44,18 @@ func Init(ctx context.Context) error {
return err
}
// List pending account removals, and process them one by one, committing each
// individually.
removals, err := bstore.QueryDB[AccountRemove](ctx, AuthDB).List()
if err != nil {
return fmt.Errorf("listing scheduled account removals: %v", err)
}
for _, removal := range removals {
if err := removeAccount(pkglog, removal.AccountName); err != nil {
pkglog.Errorx("removing old account", err, slog.String("account", removal.AccountName))
}
}
startLoginAttemptWriter()
loginAttemptCleanerStop = make(chan chan struct{})