Extract listing of GPG keys into a util class, so it can be reused.
Release-Notes: skip
Bug: Google b/262346110
Change-Id: I93d0f6af11dbd4e13ea6d5b98a6b19de41899c6a
diff --git a/java/com/google/gerrit/gpg/PublicKeyStoreUtil.java b/java/com/google/gerrit/gpg/PublicKeyStoreUtil.java
new file mode 100644
index 0000000..5333826
--- /dev/null
+++ b/java/com/google/gerrit/gpg/PublicKeyStoreUtil.java
@@ -0,0 +1,80 @@
+// 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.gpg;
+
+import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_GPGKEY;
+
+import com.google.common.flogger.FluentLogger;
+import com.google.common.io.BaseEncoding;
+import com.google.gerrit.entities.Account;
+import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIds;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.openpgp.PGPPublicKeyRing;
+import org.eclipse.jgit.util.NB;
+
+public class PublicKeyStoreUtil {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ private final ExternalIds externalIds;
+ private final Provider<PublicKeyStore> storeProvider;
+
+ @Inject
+ public PublicKeyStoreUtil(ExternalIds externalIds, Provider<PublicKeyStore> storeProvider) {
+ this.externalIds = externalIds;
+ this.storeProvider = storeProvider;
+ }
+
+ public static byte[] parseFingerprint(ExternalId gpgKeyExtId) {
+ return BaseEncoding.base16().decode(gpgKeyExtId.key().id());
+ }
+
+ public static long keyIdFromFingerprint(byte[] fp) {
+ return NB.decodeInt64(fp, fp.length - 8);
+ }
+
+ public List<PGPPublicKey> listGpgKeysForUser(Account.Id id) throws PGPException, IOException {
+ List<PGPPublicKey> keys = new ArrayList<>();
+ try (PublicKeyStore store = storeProvider.get()) {
+ for (ExternalId extId : getGpgExtIds(id)) {
+ byte[] fp = parseFingerprint(extId);
+ boolean found = false;
+ for (PGPPublicKeyRing keyRing : store.get(keyIdFromFingerprint(fp))) {
+ if (Arrays.equals(keyRing.getPublicKey().getFingerprint(), fp)) {
+ found = true;
+ keys.add(keyRing.getPublicKey());
+ break;
+ }
+ }
+ if (!found) {
+ logger.atWarning().log(
+ "No public key stored for fingerprint %s", Fingerprint.toString(fp));
+ }
+ }
+ }
+ return keys;
+ }
+
+ public Iterable<ExternalId> getGpgExtIds(Account.Id id) throws IOException {
+ return externalIds.byAccount(id, SCHEME_GPGKEY);
+ }
+}
diff --git a/java/com/google/gerrit/gpg/server/GpgKeys.java b/java/com/google/gerrit/gpg/server/GpgKeys.java
index 00a0f57..9fb8286 100644
--- a/java/com/google/gerrit/gpg/server/GpgKeys.java
+++ b/java/com/google/gerrit/gpg/server/GpgKeys.java
@@ -14,13 +14,10 @@
package com.google.gerrit.gpg.server;
-import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_GPGKEY;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.base.CharMatcher;
import com.google.common.collect.ImmutableList;
-import com.google.common.flogger.FluentLogger;
-import com.google.common.io.BaseEncoding;
import com.google.gerrit.extensions.common.GpgKeyInfo;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.AuthException;
@@ -36,10 +33,10 @@
import com.google.gerrit.gpg.GerritPublicKeyChecker;
import com.google.gerrit.gpg.PublicKeyChecker;
import com.google.gerrit.gpg.PublicKeyStore;
+import com.google.gerrit.gpg.PublicKeyStoreUtil;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.account.AccountResource;
import com.google.gerrit.server.account.externalids.ExternalId;
-import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@@ -48,36 +45,35 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
-import org.eclipse.jgit.util.NB;
@Singleton
public class GpgKeys implements ChildCollection<AccountResource, GpgKey> {
- private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private final DynamicMap<RestView<GpgKey>> views;
private final Provider<CurrentUser> self;
+ private final PublicKeyStoreUtil publicKeyStoreUtil;
private final Provider<PublicKeyStore> storeProvider;
private final GerritPublicKeyChecker.Factory checkerFactory;
- private final ExternalIds externalIds;
@Inject
GpgKeys(
DynamicMap<RestView<GpgKey>> views,
Provider<CurrentUser> self,
+ PublicKeyStoreUtil publicKeyStoreUtil,
Provider<PublicKeyStore> storeProvider,
- GerritPublicKeyChecker.Factory checkerFactory,
- ExternalIds externalIds) {
+ GerritPublicKeyChecker.Factory checkerFactory) {
this.views = views;
this.self = self;
+ this.publicKeyStoreUtil = publicKeyStoreUtil;
this.storeProvider = storeProvider;
this.checkerFactory = checkerFactory;
- this.externalIds = externalIds;
}
@Override
@@ -90,10 +86,11 @@
throws ResourceNotFoundException, PGPException, IOException {
checkVisible(self, parent);
- ExternalId gpgKeyExtId = findGpgKey(id.get(), getGpgExtIds(parent));
- byte[] fp = parseFingerprint(gpgKeyExtId);
+ ExternalId gpgKeyExtId =
+ findGpgKey(id.get(), publicKeyStoreUtil.getGpgExtIds(parent.getUser().getAccountId()));
+ byte[] fp = PublicKeyStoreUtil.parseFingerprint(gpgKeyExtId);
try (PublicKeyStore store = storeProvider.get()) {
- long keyId = keyId(fp);
+ long keyId = PublicKeyStoreUtil.keyIdFromFingerprint(fp);
for (PGPPublicKeyRing keyRing : store.get(keyId)) {
PGPPublicKey key = keyRing.getPublicKey();
if (Arrays.equals(key.getFingerprint(), fp)) {
@@ -131,10 +128,6 @@
return gpgKeyExtId;
}
- static byte[] parseFingerprint(ExternalId gpgKeyExtId) {
- return BaseEncoding.base16().decode(gpgKeyExtId.key().id());
- }
-
@Override
public DynamicMap<RestView<GpgKey>> views() {
return views;
@@ -145,29 +138,17 @@
public Response<Map<String, GpgKeyInfo>> apply(AccountResource rsrc)
throws PGPException, IOException, ResourceNotFoundException {
checkVisible(self, rsrc);
- Map<String, GpgKeyInfo> keys = new HashMap<>();
+ List<PGPPublicKey> keys =
+ publicKeyStoreUtil.listGpgKeysForUser(rsrc.getUser().getAccountId());
+ Map<String, GpgKeyInfo> res = new HashMap<>();
try (PublicKeyStore store = storeProvider.get()) {
- for (ExternalId extId : getGpgExtIds(rsrc)) {
- byte[] fp = parseFingerprint(extId);
- boolean found = false;
- for (PGPPublicKeyRing keyRing : store.get(keyId(fp))) {
- if (Arrays.equals(keyRing.getPublicKey().getFingerprint(), fp)) {
- found = true;
- GpgKeyInfo info =
- toJson(
- keyRing.getPublicKey(), checkerFactory.create(rsrc.getUser(), store), store);
- keys.put(info.id, info);
- info.id = null;
- break;
- }
- }
- if (!found) {
- logger.atWarning().log(
- "No public key stored for fingerprint %s", Fingerprint.toString(fp));
- }
+ for (PGPPublicKey key : keys) {
+ GpgKeyInfo info = toJson(key, checkerFactory.create(rsrc.getUser(), store), store);
+ res.put(info.id, info);
+ info.id = null;
}
}
- return Response.ok(keys);
+ return Response.ok(res);
}
}
@@ -194,14 +175,6 @@
}
}
- private Iterable<ExternalId> getGpgExtIds(AccountResource rsrc) throws IOException {
- return externalIds.byAccount(rsrc.getUser().getAccountId(), SCHEME_GPGKEY);
- }
-
- private static long keyId(byte[] fp) {
- return NB.decodeInt64(fp, fp.length - 8);
- }
-
static void checkVisible(Provider<CurrentUser> self, AccountResource rsrc)
throws ResourceNotFoundException {
if (!BouncyCastleUtil.havePGP()) {
diff --git a/java/com/google/gerrit/gpg/server/PostGpgKeys.java b/java/com/google/gerrit/gpg/server/PostGpgKeys.java
index d51ee6a..a45c400 100644
--- a/java/com/google/gerrit/gpg/server/PostGpgKeys.java
+++ b/java/com/google/gerrit/gpg/server/PostGpgKeys.java
@@ -46,6 +46,7 @@
import com.google.gerrit.gpg.GerritPublicKeyChecker;
import com.google.gerrit.gpg.PublicKeyChecker;
import com.google.gerrit.gpg.PublicKeyStore;
+import com.google.gerrit.gpg.PublicKeyStoreUtil;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser;
@@ -175,7 +176,8 @@
for (String id : input.delete) {
try {
ExternalId gpgKeyExtId = GpgKeys.findGpgKey(id, existingExtIds);
- fingerprints.put(gpgKeyExtId, new Fingerprint(GpgKeys.parseFingerprint(gpgKeyExtId)));
+ fingerprints.put(
+ gpgKeyExtId, new Fingerprint(PublicKeyStoreUtil.parseFingerprint(gpgKeyExtId)));
} catch (ResourceNotFoundException e) {
// Skip removal.
}