diff --git a/src/internal/kopia/conn.go b/src/internal/kopia/conn.go index ee8a9132e..7a4948787 100644 --- a/src/internal/kopia/conn.go +++ b/src/internal/kopia/conn.go @@ -578,3 +578,23 @@ func (w *conn) LoadSnapshot( func (w *conn) SnapshotRoot(man *snapshot.Manifest) (fs.Entry, error) { return snapshotfs.SnapshotRoot(w.Repository, man) } + +func (w *conn) UpdatePassword(ctx context.Context, password string, opts repository.Options) error { + if len(password) <= 0 { + return clues.New("empty password provided") + } + + kopiaRef := NewConn(w.storage) + if err := kopiaRef.Connect(ctx, opts); err != nil { + return clues.Wrap(err, "connecting kopia client") + } + + defer kopiaRef.Close(ctx) + + kopiaRepo := kopiaRef.Repository.(repo.DirectRepository) + if err := kopiaRepo.FormatManager().ChangePassword(ctx, password); err != nil { + return clues.Wrap(err, "unable to update password") + } + + return nil +} diff --git a/src/pkg/repository/repository.go b/src/pkg/repository/repository.go index 539c3c3b1..283af8e56 100644 --- a/src/pkg/repository/repository.go +++ b/src/pkg/repository/repository.go @@ -86,7 +86,7 @@ func New( st storage.Storage, opts control.Options, configFileRepoID string, -) (repo *repository, err error) { +) (singleRepo *repository, err error) { ctx = clues.Add( ctx, "acct_provider", acct.Provider.String(), @@ -253,6 +253,40 @@ func (r *repository) Connect( return nil } +// UpdatePassword will- +// - connect to the provider storage using existing password +// - update the repo with new password +func (r *repository) UpdatePassword(ctx context.Context, password string) (err error) { + ctx = clues.Add( + ctx, + "acct_provider", r.Account.Provider.String(), + "acct_id", clues.Hide(r.Account.ID()), + "storage_provider", r.Storage.Provider.String()) + + defer func() { + if crErr := crash.Recovery(ctx, recover(), "repo connect"); crErr != nil { + err = crErr + } + }() + + progressBar := observe.MessageWithCompletion(ctx, "Connecting to repository") + defer close(progressBar) + + kopiaRef := kopia.NewConn(r.Storage) + if err := kopiaRef.Connect(ctx, r.Opts.Repo); err != nil { + return clues.Wrap(err, "connecting kopia client") + } + + err = kopiaRef.UpdatePassword(ctx, password, r.Opts.Repo) + if err != nil { + return clues.Wrap(err, "updating on kopia") + } + + defer kopiaRef.Close(ctx) + + return nil +} + func (r *repository) Close(ctx context.Context) error { if err := r.Bus.Close(); err != nil { logger.Ctx(ctx).With("err", err).Debugw("closing the event bus", clues.In(ctx).Slice()...) diff --git a/src/pkg/repository/repository_test.go b/src/pkg/repository/repository_test.go index 97456fe70..b76f2bb2c 100644 --- a/src/pkg/repository/repository_test.go +++ b/src/pkg/repository/repository_test.go @@ -240,6 +240,44 @@ func (suite *RepositoryIntegrationSuite) TestConnect() { assert.NoError(t, err, clues.ToCore(err)) } +func (suite *RepositoryIntegrationSuite) TestRepository_UpdatePassword() { + t := suite.T() + + ctx, flush := tester.NewContext(t) + defer flush() + + acct := tconfig.NewM365Account(t) + + // need to initialize the repository before we can test connecting to it. + st := storeTD.NewPrefixedS3Storage(t) + r, err := New( + ctx, + acct, + st, + control.DefaultOptions(), + NewRepoID) + require.NoError(t, err, clues.ToCore(err)) + + err = r.Initialize(ctx, InitConfig{}) + require.NoError(t, err, clues.ToCore(err)) + + // now re-connect + err = r.Connect(ctx, ConnConfig{}) + assert.NoError(t, err, clues.ToCore(err)) + + err = r.UpdatePassword(ctx, "newpass") + require.NoError(t, err, clues.ToCore(err)) + + tmp := st.Config["common_corsoPassphrase"] + st.Config["common_corsoPassphrase"] = "newpass" + + // now reconnect with new pass + err = r.Connect(ctx, ConnConfig{}) + assert.NoError(t, err, clues.ToCore(err)) + + st.Config["common_corsoPassphrase"] = tmp +} + func (suite *RepositoryIntegrationSuite) TestConnect_sameID() { t := suite.T()