From 449881bd8dc849f276df748c41d8279002bd0f3d Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Wed, 3 Feb 2021 16:26:15 +0100 Subject: [PATCH] Add deleteUserIds(keyId, userIdSelectionStrategy, protector) method to SecretKeyRingEditor --- .../secretkeyring/SecretKeyRingEditor.java | 13 ++++--- .../SecretKeyRingEditorInterface.java | 7 +++- .../userid/UserIdSelectionStrategy.java | 35 +++++++++++++++++++ 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.java b/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.java index 0522ea51..e8439e00 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.java @@ -16,6 +16,7 @@ package org.pgpainless.key.modification.secretkeyring; import static org.pgpainless.key.util.KeyRingUtils.unlockSecretKey; +import static org.pgpainless.util.CollectionUtils.iteratorToList; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; @@ -65,6 +66,7 @@ import org.pgpainless.key.util.RevocationAttributes; import org.pgpainless.key.util.SignatureUtils; import org.pgpainless.util.Passphrase; import org.pgpainless.util.SignatureSubpacketGeneratorUtil; +import org.pgpainless.util.selection.userid.UserIdSelectionStrategy; public class SecretKeyRingEditor implements SecretKeyRingEditorInterface { @@ -146,7 +148,7 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface { } @Override - public SecretKeyRingEditorInterface deleteUserId(long keyId, String userId, SecretKeyRingProtector secretKeyRingProtector) { + public SecretKeyRingEditorInterface deleteUserIds(long keyId, UserIdSelectionStrategy selectionStrategy, SecretKeyRingProtector secretKeyRingProtector) { List publicKeys = new ArrayList<>(); Iterator publicKeyIterator = secretKeyRing.getPublicKeys(); boolean foundKey = false; @@ -154,10 +156,13 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface { PGPPublicKey publicKey = publicKeyIterator.next(); if (publicKey.getKeyID() == keyId) { foundKey = true; - if (!hasUserId(userId, publicKey)) { - throw new NoSuchElementException("Key " + Long.toHexString(keyId) + " does not have a user-id attribute of value '" + userId + "'"); + List matchingUserIds = selectionStrategy.selectUserIds(iteratorToList(publicKey.getUserIDs())); + if (matchingUserIds.isEmpty()) { + throw new NoSuchElementException("Key " + Long.toHexString(keyId) + " does not have a matching user-id attribute."); + } + for (String userId : matchingUserIds) { + publicKey = PGPPublicKey.removeCertification(publicKey, userId); } - publicKey = PGPPublicKey.removeCertification(publicKey, userId); } publicKeys.add(publicKey); } diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditorInterface.java b/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditorInterface.java index 2e4771a6..e8c1e280 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditorInterface.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditorInterface.java @@ -32,6 +32,7 @@ import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.util.RevocationAttributes; import org.pgpainless.key.util.UserId; import org.pgpainless.util.Passphrase; +import org.pgpainless.util.selection.userid.UserIdSelectionStrategy; public interface SecretKeyRingEditorInterface { @@ -75,7 +76,11 @@ public interface SecretKeyRingEditorInterface { return deleteUserId(fingerprint.getKeyId(), userId, secretKeyRingProtector); } - SecretKeyRingEditorInterface deleteUserId(long keyId, String userId, SecretKeyRingProtector secretKeyRingProtector); + default SecretKeyRingEditorInterface deleteUserId(long keyId, String userId, SecretKeyRingProtector secretKeyRingProtector) { + return deleteUserIds(keyId, UserIdSelectionStrategy.exactMatch(userId), secretKeyRingProtector); + } + + SecretKeyRingEditorInterface deleteUserIds(long keyId, UserIdSelectionStrategy selectionStrategy, SecretKeyRingProtector secretKeyRingProtector); /** * Add a subkey to the key ring. diff --git a/pgpainless-core/src/main/java/org/pgpainless/util/selection/userid/UserIdSelectionStrategy.java b/pgpainless-core/src/main/java/org/pgpainless/util/selection/userid/UserIdSelectionStrategy.java index cbbb15bd..20137b4f 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/util/selection/userid/UserIdSelectionStrategy.java +++ b/pgpainless-core/src/main/java/org/pgpainless/util/selection/userid/UserIdSelectionStrategy.java @@ -83,4 +83,39 @@ public abstract class UserIdSelectionStrategy { public static UserIdSelectionStrategy containsEmailAddress(String email) { return containsSubstring(email.matches("^<.+>$") ? email : '<' + email + '>'); } + + public static UserIdSelectionStrategy validUserId(PGPKeyRing keyRing) { + return new UserIdSelectionStrategy() { + @Override + protected boolean accept(String userId) { + return PGPainless.inspectKeyRing(keyRing).isUserIdValid(userId); + } + }; + } + + public static UserIdSelectionStrategy and(UserIdSelectionStrategy... strategies) { + return new UserIdSelectionStrategy() { + @Override + protected boolean accept(String userId) { + boolean accept = true; + for (UserIdSelectionStrategy strategy : strategies) { + accept &= strategy.accept(userId); + } + return accept; + } + }; + } + + public static UserIdSelectionStrategy or(UserIdSelectionStrategy... strategies) { + return new UserIdSelectionStrategy() { + @Override + protected boolean accept(String userId) { + boolean accept = false; + for (UserIdSelectionStrategy strategy : strategies) { + accept |= strategy.accept(userId); + } + return accept; + } + }; + } }