All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gerrit.server.restapi.account.DeleteAccount Maven / Gradle / Ivy

There is a newer version: 3.11.0-rc3
Show newest version
// Copyright (C) 2023 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.gerrit.server.restapi.account;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Table;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.common.Input;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.gpg.PublicKeyStoreUtil;
import com.google.gerrit.index.query.QueryParseException;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.StarredChangesReader;
import com.google.gerrit.server.StarredChangesWriter;
import com.google.gerrit.server.UserInitiated;
import com.google.gerrit.server.account.AccountException;
import com.google.gerrit.server.account.AccountResource;
import com.google.gerrit.server.account.AccountSshKey;
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.VersionedAuthorizedKeys;
import com.google.gerrit.server.change.AccountPatchReviewStore;
import com.google.gerrit.server.edit.ChangeEdit;
import com.google.gerrit.server.edit.ChangeEditUtil;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.plugincontext.PluginItemContext;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.query.change.InternalChangeQuery;
import com.google.gerrit.server.ssh.SshKeyCache;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.io.IOException;
import java.util.List;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;

/**
 * REST endpoint for deleting an account.
 *
 * 

This REST endpoint handles {@code DELETE /accounts/} requests. Currently, * only self deletions are allowed. */ @Singleton public class DeleteAccount implements RestModifyView { private final Provider self; private final Provider serverIdent; private final Provider accountsUpdateProvider; private final VersionedAuthorizedKeys.Accessor authorizedKeys; private final SshKeyCache sshKeyCache; private final StarredChangesReader starredChangesReader; private final StarredChangesWriter starredChangesWriter; private final DeleteDraftCommentsUtil deleteDraftCommentsUtil; private final GitRepositoryManager gitManager; private final Provider queryProvider; private final ChangeEditUtil changeEditUtil; private final PluginItemContext accountPatchReviewStore; private final PublicKeyStoreUtil publicKeyStoreUtil; @Inject public DeleteAccount( Provider self, @GerritPersonIdent Provider serverIdent, @UserInitiated Provider accountsUpdateProvider, VersionedAuthorizedKeys.Accessor authorizedKeys, SshKeyCache sshKeyCache, StarredChangesReader starredChangesReader, StarredChangesWriter starredChangesWriter, DeleteDraftCommentsUtil deleteDraftCommentsUtil, GitRepositoryManager gitManager, Provider queryProvider, ChangeEditUtil changeEditUtil, PluginItemContext accountPatchReviewStore, PublicKeyStoreUtil publicKeyStoreUtil) { this.self = self; this.serverIdent = serverIdent; this.accountsUpdateProvider = accountsUpdateProvider; this.authorizedKeys = authorizedKeys; this.sshKeyCache = sshKeyCache; this.starredChangesReader = starredChangesReader; this.starredChangesWriter = starredChangesWriter; this.deleteDraftCommentsUtil = deleteDraftCommentsUtil; this.gitManager = gitManager; this.queryProvider = queryProvider; this.changeEditUtil = changeEditUtil; this.accountPatchReviewStore = accountPatchReviewStore; this.publicKeyStoreUtil = publicKeyStoreUtil; } @Override @CanIgnoreReturnValue public Response apply(AccountResource rsrc, Input unusedInput) throws AuthException, AccountException { IdentifiedUser user = rsrc.getUser(); if (!self.get().hasSameAccountId(user)) { throw new AuthException("Delete account is only permitted for self"); } Account.Id userId = user.getAccountId(); try { deletePgpKeys(user); deleteSshKeys(user); deleteStarredChanges(userId); deleteChangeEdits(userId); deleteDraftCommentsUtil.deleteDraftComments(user, null); accountPatchReviewStore.run(a -> a.clearReviewedBy(userId)); accountsUpdateProvider .get() .delete("Deleting user through `DELETE /accounts/{ID}`", user.getAccountId()); } catch (Exception e) { throw new AccountException("Could not delete account", e); } return Response.none(); } private void deletePgpKeys(IdentifiedUser user) { if (!publicKeyStoreUtil.hasInitializedPublicKeyStore()) { return; } try { List deletedKeyResults = publicKeyStoreUtil.deleteAllPgpKeysForUser( user.getAccountId(), serverIdent.get(), serverIdent.get()); for (RefUpdate.Result saveResult : deletedKeyResults) { if (saveResult != RefUpdate.Result.NO_CHANGE && saveResult != RefUpdate.Result.FAST_FORWARD) { throw new StorageException(String.format("Failed to delete PGP key: %s", saveResult)); } } } catch (Exception e) { throw new StorageException("Failed to delete PGP keys.", e); } } private void deleteSshKeys(IdentifiedUser user) throws ConfigInvalidException, IOException { List keys = authorizedKeys.getKeys(user.getAccountId()); for (AccountSshKey key : keys) { authorizedKeys.deleteKey(user.getAccountId(), key.seq()); } user.getUserName().ifPresent(sshKeyCache::evict); } private void deleteStarredChanges(Account.Id accountId) { ImmutableSet staredChanges = starredChangesReader.byAccountId(accountId, false); for (Change.Id change : staredChanges) { starredChangesWriter.unstar(self.get().getAccountId(), change); } } private void deleteChangeEdits(Account.Id accountId) throws IOException, QueryParseException { // Note: in case of a stale index, the results of this query might be incomplete. List changesWithEdits = queryProvider.get().byOpenEditByUser(accountId); for (ChangeData cd : changesWithEdits) { for (Table.Cell edit : cd.editRefs().cellSet()) { if (!accountId.equals(edit.getRowKey())) { continue; } try (Repository repo = gitManager.openRepository(cd.project()); RevWalk rw = new RevWalk(repo)) { RevCommit commit = rw.parseCommit(edit.getValue().getObjectId()); changeEditUtil.delete( new ChangeEdit( cd.change(), edit.getValue().getName(), commit, cd.patchSet(edit.getColumnKey()))); } } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy