From 4d0f8beb0a8a2b670c224d133ae8e79fd54d1d45 Mon Sep 17 00:00:00 2001 From: Eric T Date: Thu, 21 Aug 2025 16:10:26 +0100 Subject: [PATCH] fix: add signing exception class --- .../src/main/java/nostr/api/NostrIF.java | 2 +- ...gWebSocketClientEventVerificationTest.java | 44 +++++++++++++++++++ .../src/main/java/nostr/id/Identity.java | 6 +-- .../main/java/nostr/id/SigningException.java | 10 +++++ .../src/test/java/nostr/id/IdentityTest.java | 13 +++--- 5 files changed, 65 insertions(+), 10 deletions(-) create mode 100644 nostr-java-id/src/main/java/nostr/id/SigningException.java diff --git a/nostr-java-api/src/main/java/nostr/api/NostrIF.java b/nostr-java-api/src/main/java/nostr/api/NostrIF.java index 7a28e197b..f297dfb21 100644 --- a/nostr-java-api/src/main/java/nostr/api/NostrIF.java +++ b/nostr-java-api/src/main/java/nostr/api/NostrIF.java @@ -20,7 +20,7 @@ public interface NostrIF { List sendRequest(@NonNull Filters filters, @NonNull String subscriptionId, Map relays); List sendRequest(@NonNull List filtersList, @NonNull String subscriptionId); List sendRequest(@NonNull List filtersList, @NonNull String subscriptionId, Map relays); - NostrIF sign(@NonNull Identity identity, @NonNull ISignable signable) throws Exception; + NostrIF sign(@NonNull Identity identity, @NonNull ISignable signable); boolean verify(@NonNull GenericEvent event); Identity getSender(); Map getRelays(); diff --git a/nostr-java-api/src/test/java/nostr/api/unit/NostrSpringWebSocketClientEventVerificationTest.java b/nostr-java-api/src/test/java/nostr/api/unit/NostrSpringWebSocketClientEventVerificationTest.java index 47d46f5f1..a36f71dbf 100644 --- a/nostr-java-api/src/test/java/nostr/api/unit/NostrSpringWebSocketClientEventVerificationTest.java +++ b/nostr-java-api/src/test/java/nostr/api/unit/NostrSpringWebSocketClientEventVerificationTest.java @@ -5,6 +5,14 @@ import nostr.config.Constants; import nostr.event.impl.GenericEvent; import nostr.id.Identity; +import nostr.id.SigningException; +import nostr.base.ISignable; +import nostr.base.Signature; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.function.Consumer; +import java.util.function.Supplier; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -41,4 +49,40 @@ void sendEventReturnsEmptyListWhenSigned() { List responses = client.sendEvent(event); assertTrue(responses.isEmpty()); } + + @Test + // Verifies that SigningException bubbles up from the client when signing fails + void signPropagatesSigningException() { + String invalidPriv = "0000000000000000000000000000000000000000000000000000000000000000"; + Identity identity = Identity.create(invalidPriv); + + ISignable signable = new ISignable() { + private Signature signature; + + @Override + public Signature getSignature() { + return signature; + } + + @Override + public void setSignature(Signature signature) { + this.signature = signature; + } + + @Override + public Consumer getSignatureConsumer() { + return this::setSignature; + } + + @Override + public Supplier getByteArraySupplier() { + return () -> ByteBuffer.wrap("msg".getBytes(StandardCharsets.UTF_8)); + } + }; + + NoteService service = Mockito.mock(NoteService.class); + NostrSpringWebSocketClient client = new NostrSpringWebSocketClient(service); + + assertThrows(SigningException.class, () -> client.sign(identity, signable)); + } } diff --git a/nostr-java-id/src/main/java/nostr/id/Identity.java b/nostr-java-id/src/main/java/nostr/id/Identity.java index be58c715b..e2ad8f64c 100644 --- a/nostr-java-id/src/main/java/nostr/id/Identity.java +++ b/nostr-java-id/src/main/java/nostr/id/Identity.java @@ -88,7 +88,6 @@ public PublicKey getPublicKey() { return cachedPublicKey; } - // TODO: exceptions refactor /** * Signs the supplied {@link ISignable} using this identity's private key. * The resulting {@link Signature} is returned and also provided to the @@ -96,7 +95,8 @@ public PublicKey getPublicKey() { * * @param signable the entity to sign * @return the generated signature - * @throws Exception if the signature cannot be created + * @throws IllegalStateException if the SHA-256 algorithm is unavailable + * @throws SigningException if the signature cannot be created */ public Signature sign(@NonNull ISignable signable) { try { @@ -117,7 +117,7 @@ public Signature sign(@NonNull ISignable signable) { throw new IllegalStateException("SHA-256 algorithm not available", ex); } catch (Exception ex) { log.error("Signing failed", ex); - throw new IllegalArgumentException("Failed to sign with provided key", ex); + throw new SigningException("Failed to sign with provided key", ex); } } diff --git a/nostr-java-id/src/main/java/nostr/id/SigningException.java b/nostr-java-id/src/main/java/nostr/id/SigningException.java new file mode 100644 index 000000000..500ef06a3 --- /dev/null +++ b/nostr-java-id/src/main/java/nostr/id/SigningException.java @@ -0,0 +1,10 @@ +package nostr.id; + +import lombok.experimental.StandardException; + +/** + * Exception thrown when signing an {@link nostr.base.ISignable} fails. + */ +@StandardException +public class SigningException extends RuntimeException { +} diff --git a/nostr-java-id/src/test/java/nostr/id/IdentityTest.java b/nostr-java-id/src/test/java/nostr/id/IdentityTest.java index 101d44235..96da3cee4 100644 --- a/nostr-java-id/src/test/java/nostr/id/IdentityTest.java +++ b/nostr-java-id/src/test/java/nostr/id/IdentityTest.java @@ -111,10 +111,11 @@ public void testGetPublicKeyFailure() { Assertions.assertThrows(IllegalStateException.class, identity::getPublicKey); } - @Test - public void testSignWithInvalidKeyFails() { - String invalidPriv = "0000000000000000000000000000000000000000000000000000000000000000"; - Identity identity = Identity.create(invalidPriv); + @Test + // Ensures that signing with an invalid private key throws SigningException + public void testSignWithInvalidKeyFails() { + String invalidPriv = "0000000000000000000000000000000000000000000000000000000000000000"; + Identity identity = Identity.create(invalidPriv); ISignable signable = new ISignable() { private Signature signature; @@ -140,6 +141,6 @@ public Supplier getByteArraySupplier() { } }; - Assertions.assertThrows(IllegalArgumentException.class, () -> identity.sign(signable)); - } + Assertions.assertThrows(SigningException.class, () -> identity.sign(signable)); + } } \ No newline at end of file