From a5ee3add3e01b598948faa2ebb1c8bb3792b7a72 Mon Sep 17 00:00:00 2001 From: erict875 Date: Sat, 23 Mar 2024 01:19:52 +0000 Subject: [PATCH 1/3] Multiple filters per REQ request #88 --- .../src/main/java/nostr/api/EventNostr.java | 3 +- .../src/main/java/nostr/api/NIP01.java | 8 ++- .../src/main/java/nostr/api/NIP04.java | 3 +- .../src/main/java/nostr/api/NIP44.java | 10 +-- .../src/main/java/nostr/api/Nostr.java | 31 +++++--- .../nostr/api/factory/impl/NIP01Impl.java | 6 +- .../nostr/api/factory/impl/NIP15Impl.java | 7 -- .../src/main/java/nostr/base/BaseKey.java | 8 ++- .../src/main/java/nostr/base/IKey.java | 2 +- .../src/main/java/nostr/client/Client.java | 44 ++++++------ .../encryption/nip44/MessageCipher44.java | 6 +- .../src/main/java/nostr/event/BaseEvent.java | 2 - .../java/nostr/event/impl/EphemeralEvent.java | 2 +- .../main/java/nostr/event/impl/Filters.java | 4 ++ .../impl/InternetIdentifierMetadataEvent.java | 2 +- .../impl/ParameterizedReplaceableEvent.java | 2 +- .../nostr/event/impl/ReplaceableEvent.java | 2 +- .../event/json/codec/BaseMessageDecoder.java | 29 +++----- .../event/json/codec/BaseMessageEncoder.java | 27 +++++-- .../event/json/codec/FiltersEncoder.java | 9 +-- .../event/json/codec/FiltersListDecoder.java | 25 +++++++ .../event/json/codec/FiltersListEncoder.java | 69 ++++++++++++++++++ .../CustomEventListDeserializer.java | 26 +++++++ .../CustomFiltersListDeserializer.java | 44 ++++++++++++ .../CustomKindListDeserializer.java | 24 +++++++ .../CustomPublicKeyListDeserializer.java | 26 +++++++ .../main/java/nostr/event/list/BaseList.java | 9 ++- .../main/java/nostr/event/list/EventList.java | 13 +++- .../java/nostr/event/list/FiltersList.java | 14 +++- .../nostr/event/list/GenericTagQueryList.java | 10 ++- .../main/java/nostr/event/list/KindList.java | 13 +++- .../java/nostr/event/list/PublicKeyList.java | 13 +++- .../java/nostr/event/message/ReqMessage.java | 12 +++- .../java/nostr/event/util/Nip05Validator.java | 16 ++--- .../java/nostr/examples/NostrApiExamples.java | 10 +-- .../java/nostr/test/event/ApiEventTest.java | 6 +- .../java/nostr/test/event/DecodeTest.java | 2 +- .../java/nostr/test/json/JsonParseTest.java | 70 +++++++++++++++++-- .../provider/DefaultCommandHandler.java | 2 +- .../handler/command/spi/ICommandHandler.java | 8 +-- 40 files changed, 477 insertions(+), 142 deletions(-) create mode 100644 nostr-java-event/src/main/java/nostr/event/json/codec/FiltersListDecoder.java create mode 100644 nostr-java-event/src/main/java/nostr/event/json/codec/FiltersListEncoder.java create mode 100644 nostr-java-event/src/main/java/nostr/event/json/deserializer/CustomEventListDeserializer.java create mode 100644 nostr-java-event/src/main/java/nostr/event/json/deserializer/CustomFiltersListDeserializer.java create mode 100644 nostr-java-event/src/main/java/nostr/event/json/deserializer/CustomKindListDeserializer.java create mode 100644 nostr-java-event/src/main/java/nostr/event/json/deserializer/CustomPublicKeyListDeserializer.java diff --git a/nostr-java-api/src/main/java/nostr/api/EventNostr.java b/nostr-java-api/src/main/java/nostr/api/EventNostr.java index e34d556c0..af693101d 100644 --- a/nostr-java-api/src/main/java/nostr/api/EventNostr.java +++ b/nostr-java-api/src/main/java/nostr/api/EventNostr.java @@ -19,14 +19,13 @@ /** * @author guilhermegps */ +@Getter @NoArgsConstructor public abstract class EventNostr extends Nostr { - @Getter @Setter private T event; - @Getter private PublicKey recipient; public EventNostr(@NonNull Identity sender) { diff --git a/nostr-java-api/src/main/java/nostr/api/NIP01.java b/nostr-java-api/src/main/java/nostr/api/NIP01.java index a6b4291bf..76f12ef31 100644 --- a/nostr-java-api/src/main/java/nostr/api/NIP01.java +++ b/nostr-java-api/src/main/java/nostr/api/NIP01.java @@ -28,6 +28,7 @@ import nostr.event.NIP01Event; import nostr.event.impl.Filters; import nostr.event.list.EventList; +import nostr.event.list.FiltersList; import nostr.event.list.GenericTagQueryList; import nostr.event.list.KindList; import nostr.event.list.PublicKeyList; @@ -222,6 +223,7 @@ public static Filters createFilters(EventList events, PublicKeyList authors, Kin .build(); } + /** * Create an event message to send events requested by clients * @@ -239,11 +241,11 @@ public static EventMessage createEventMessage(@NonNull IEvent event, @NonNull St * Create a REQ message to request events and subscribe to new updates * * @param subscriptionId the subscription id - * @param filters the filters object + * @param filtersList the filters list * @return a REQ message */ - public static ReqMessage createReqMessage(@NonNull String subscriptionId, @NonNull Filters filters) { - return new ReqMessageFactory(subscriptionId, filters).create(); + public static ReqMessage createReqMessage(@NonNull String subscriptionId, @NonNull FiltersList filtersList) { + return new ReqMessageFactory(subscriptionId, filtersList).create(); } /** diff --git a/nostr-java-api/src/main/java/nostr/api/NIP04.java b/nostr-java-api/src/main/java/nostr/api/NIP04.java index f6861a366..8567d51f0 100644 --- a/nostr-java-api/src/main/java/nostr/api/NIP04.java +++ b/nostr-java-api/src/main/java/nostr/api/NIP04.java @@ -91,9 +91,8 @@ public static String encrypt(@NonNull IIdentity senderId, @NonNull String messag * @param rcptId * @param dm the encrypted direct message * @return the DM content in clear-text - * @throws NostrException */ - public static String decrypt(@NonNull IIdentity rcptId, @NonNull DirectMessageEvent dm) throws NostrException { + public static String decrypt(@NonNull IIdentity rcptId, @NonNull DirectMessageEvent dm) { return NIP04.decrypt(rcptId, (GenericEvent) dm); } diff --git a/nostr-java-api/src/main/java/nostr/api/NIP44.java b/nostr-java-api/src/main/java/nostr/api/NIP44.java index 46cc50162..734932cdd 100644 --- a/nostr-java-api/src/main/java/nostr/api/NIP44.java +++ b/nostr-java-api/src/main/java/nostr/api/NIP44.java @@ -73,7 +73,7 @@ public NIP44 encrypt() { } public static String encrypt(@NonNull IIdentity senderId, @NonNull String message, @NonNull PublicKey recipient) { - MessageCipher cipher = new MessageCipher44(senderId.getPrivateKey().toString(), recipient.toString()); + MessageCipher cipher = new MessageCipher44(senderId.getPrivateKey().getRawData(), recipient.getRawData()); return cipher.encrypt(message); } @@ -97,7 +97,7 @@ public static String decrypt(@NonNull IIdentity rcptId, @NonNull EncryptedPayloa * @return the ep content in clear-text */ public static String decrypt(@NonNull IIdentity identity, @NonNull String encrypteEPessage, @NonNull PublicKey recipient) { - MessageCipher cipher = new MessageCipher44(identity.getPrivateKey().toString(), recipient.toString()); + MessageCipher cipher = new MessageCipher44(identity.getPrivateKey().getRawData(), recipient.getRawData()); return cipher.decrypt(encrypteEPessage); } @@ -112,14 +112,14 @@ public static String decrypt(@NonNull IIdentity rcptId, @NonNull GenericEvent ev boolean rcptFlag = amITheRecipient(rcptId, event); if (!rcptFlag) { // I am the message sender - MessageCipher cipher = new MessageCipher44(rcptId.getPrivateKey().toString(), pTag.getPublicKey().toString()); + MessageCipher cipher = new MessageCipher44(rcptId.getPrivateKey().getRawData(), pTag.getPublicKey().getRawData()); return cipher.decrypt(event.getContent()); } // I am the message recipient var sender = event.getPubKey(); log.log(Level.FINE, "The message is being decrypted for {0}", sender); - MessageCipher cipher = new MessageCipher44(rcptId.getPrivateKey().toString(), sender.toString()); + MessageCipher cipher = new MessageCipher44(rcptId.getPrivateKey().getRawData(), sender.getRawData()); return cipher.decrypt(event.getContent()); } @@ -128,7 +128,7 @@ private static void encryptDirectMessage(@NonNull IIdentity senderId, @NonNull E ITag pkTag = ep.getTags().get(0); if (pkTag instanceof PubKeyTag pubKeyTag) { var rcptPublicKey = pubKeyTag.getPublicKey(); - MessageCipher cipher = new MessageCipher44(senderId.getPrivateKey().toString(), rcptPublicKey.toString()); + MessageCipher cipher = new MessageCipher44(senderId.getPrivateKey().getRawData(), rcptPublicKey.getRawData()); var encryptedContent = cipher.encrypt(ep.getContent()); ep.setContent(encryptedContent); } diff --git a/nostr-java-api/src/main/java/nostr/api/Nostr.java b/nostr-java-api/src/main/java/nostr/api/Nostr.java index e8db41578..d6a7a0b8e 100644 --- a/nostr-java-api/src/main/java/nostr/api/Nostr.java +++ b/nostr-java-api/src/main/java/nostr/api/Nostr.java @@ -24,9 +24,10 @@ import nostr.event.json.codec.BaseTagDecoder; import nostr.event.json.codec.BaseTagEncoder; import nostr.event.json.codec.FiltersDecoder; -import nostr.event.json.codec.FiltersEncoder; +import nostr.event.json.codec.FiltersListEncoder; import nostr.event.json.codec.GenericEventDecoder; import nostr.event.json.codec.GenericTagQueryEncoder; +import nostr.event.list.FiltersList; import nostr.id.IIdentity; import java.util.List; @@ -83,12 +84,24 @@ public void send(@NonNull IEvent event) { } public void send(@NonNull Filters filters, @NonNull String subscriptionId) { - getClient().send(filters, subscriptionId); + FiltersList filtersList = new FiltersList(); + filtersList.add(filters); + getClient().send(filtersList, subscriptionId); + } + + public void send(@NonNull FiltersList filtersList, @NonNull String subscriptionId) { + getClient().send(filtersList, subscriptionId); } public void send(@NonNull Filters filters, @NonNull String subscriptionId, Map relays) { + FiltersList filtersList = new FiltersList(); + filtersList.add(filters); + send(filtersList, subscriptionId, relays); + } + + public void send(@NonNull FiltersList filtersList, @NonNull String subscriptionId, Map relays) { setRelays(relays); - getClient().send(filters, subscriptionId); + getClient().send(filtersList, subscriptionId); } /** @@ -184,19 +197,19 @@ public static BaseTag decodeTag(@NonNull String json) { // Filters /** - * @param filters + * @param filtersList * @param relay */ - public static String encode(@NonNull Filters filters, Relay relay) { - final var enc = new FiltersEncoder(filters, relay); + public static String encode(@NonNull FiltersList filtersList, Relay relay) { + final var enc = new FiltersListEncoder(filtersList, relay); return enc.encode(); } /** - * @param filters + * @param filtersList */ - public static String encode(@NonNull Filters filters) { - return Nostr.Json.encode(filters, null); + public static String encode(@NonNull FiltersList filtersList) { + return Nostr.Json.encode(filtersList, null); } /** diff --git a/nostr-java-api/src/main/java/nostr/api/factory/impl/NIP01Impl.java b/nostr-java-api/src/main/java/nostr/api/factory/impl/NIP01Impl.java index af57dcb6d..5d47b5837 100644 --- a/nostr-java-api/src/main/java/nostr/api/factory/impl/NIP01Impl.java +++ b/nostr-java-api/src/main/java/nostr/api/factory/impl/NIP01Impl.java @@ -18,11 +18,11 @@ import nostr.event.BaseTag; import nostr.event.Marker; import nostr.event.impl.EphemeralEvent; -import nostr.event.impl.Filters; import nostr.event.impl.MetadataEvent; import nostr.event.impl.ParameterizedReplaceableEvent; import nostr.event.impl.ReplaceableEvent; import nostr.event.impl.TextNoteEvent; +import nostr.event.list.FiltersList; import nostr.event.message.CloseMessage; import nostr.event.message.EoseMessage; import nostr.event.message.EventMessage; @@ -153,11 +153,11 @@ public EventMessage create() { public static class ReqMessageFactory extends MessageFactory { private final String subscriptionId; - private final Filters filters; + private final FiltersList filtersList; @Override public ReqMessage create() { - return new ReqMessage(subscriptionId, filters); + return new ReqMessage(subscriptionId, filtersList); } } diff --git a/nostr-java-api/src/main/java/nostr/api/factory/impl/NIP15Impl.java b/nostr-java-api/src/main/java/nostr/api/factory/impl/NIP15Impl.java index 06bfd72ff..e3d1a30a5 100644 --- a/nostr-java-api/src/main/java/nostr/api/factory/impl/NIP15Impl.java +++ b/nostr-java-api/src/main/java/nostr/api/factory/impl/NIP15Impl.java @@ -47,13 +47,6 @@ public VerifyPaymentOrShippedEventFactory(@NonNull List tags, VerifyPay this.customer = customer; } - @Deprecated - public VerifyPaymentOrShippedEventFactory(@NonNull IIdentity sender, @NonNull VerifyPaymentOrShippedEvent.PaymentShipmentStatus status, @NonNull CustomerOrderEvent.Customer customer) { - super(sender, status.toString()); - this.status = status; - this.customer = customer; - } - @Override public VerifyPaymentOrShippedEvent create() { return new VerifyPaymentOrShippedEvent(getSender(), customer, status); diff --git a/nostr-java-base/src/main/java/nostr/base/BaseKey.java b/nostr-java-base/src/main/java/nostr/base/BaseKey.java index f0a2d0894..a8ca1142d 100644 --- a/nostr-java-base/src/main/java/nostr/base/BaseKey.java +++ b/nostr-java-base/src/main/java/nostr/base/BaseKey.java @@ -29,7 +29,7 @@ public abstract class BaseKey implements IKey { protected final Bech32Prefix prefix; @Override - public String getBech32() { + public String toBech32String() { try { return Bech32.toBech32(prefix, rawData); } catch (NostrException ex) { @@ -37,9 +37,13 @@ public String getBech32() { } } - @JsonValue @Override + @JsonValue public String toString() { + return toHexString(); + } + + public String toHexString() { return NostrUtil.bytesToHex(rawData); } diff --git a/nostr-java-base/src/main/java/nostr/base/IKey.java b/nostr-java-base/src/main/java/nostr/base/IKey.java index 72a9a4f96..fad1a05ed 100644 --- a/nostr-java-base/src/main/java/nostr/base/IKey.java +++ b/nostr-java-base/src/main/java/nostr/base/IKey.java @@ -11,5 +11,5 @@ public interface IKey extends Serializable { byte[] getRawData(); - String getBech32(); + String toBech32String(); } diff --git a/nostr-java-client/src/main/java/nostr/client/Client.java b/nostr-java-client/src/main/java/nostr/client/Client.java index 70c886c63..a8506edf8 100644 --- a/nostr-java-client/src/main/java/nostr/client/Client.java +++ b/nostr-java-client/src/main/java/nostr/client/Client.java @@ -1,23 +1,5 @@ package nostr.client; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLConnection; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.logging.Level; -import java.util.stream.Collectors; - import lombok.Getter; import lombok.NonNull; import lombok.extern.java.Log; @@ -25,7 +7,7 @@ import nostr.base.Relay; import nostr.event.BaseMessage; import nostr.event.impl.ClientAuthenticationEvent; -import nostr.event.impl.Filters; +import nostr.event.list.FiltersList; import nostr.event.message.ClientAuthenticationMessage; import nostr.event.message.CloseMessage; import nostr.event.message.EventMessage; @@ -37,6 +19,24 @@ import nostr.ws.handler.spi.IRequestHandler; import nostr.ws.request.handler.provider.DefaultRequestHandler; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.logging.Level; +import java.util.stream.Collectors; + @Log public class Client { @@ -122,8 +122,8 @@ public void send(@NonNull IEvent event, String subsciptionId) { send(message); } - public void send(@NonNull Filters filters, String subscriptionId) { - ReqMessage message = new ReqMessage(subscriptionId, filters); + public void send(@NonNull FiltersList filtersList, String subscriptionId) { + ReqMessage message = new ReqMessage(subscriptionId, filtersList); send(message); } @@ -168,7 +168,7 @@ public void auth(Identity identity, String challenge) { this.send(authMsg); } - public void auth(String challenge, Relay relay) throws NostrException { + public void auth(String challenge, Relay relay) { auth(Identity.getInstance(), challenge, relay); } diff --git a/nostr-java-encryption-nip44/src/main/java/nostr/encryption/nip44/MessageCipher44.java b/nostr-java-encryption-nip44/src/main/java/nostr/encryption/nip44/MessageCipher44.java index 34c307a72..6de3c232c 100644 --- a/nostr-java-encryption-nip44/src/main/java/nostr/encryption/nip44/MessageCipher44.java +++ b/nostr-java-encryption-nip44/src/main/java/nostr/encryption/nip44/MessageCipher44.java @@ -16,8 +16,8 @@ public class MessageCipher44 implements MessageCipher { private static final int NONCE_LENGTH = 32; - private final String senderPrivateKey; - private final String recipientPublicKey; + private final byte[] senderPrivateKey; + private final byte[] recipientPublicKey; @Override public String encrypt(@NonNull String message) { @@ -42,7 +42,7 @@ public String decrypt(@NonNull String payload) { private byte[] getConversationKey() { try { - return EncryptedPayloads.getConversationKey(senderPrivateKey, "02" + recipientPublicKey); + return EncryptedPayloads.getConversationKey(NostrUtil.bytesToHex(senderPrivateKey), "02" + NostrUtil.bytesToHex(recipientPublicKey)); } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { throw new RuntimeException(e); } diff --git a/nostr-java-event/src/main/java/nostr/event/BaseEvent.java b/nostr-java-event/src/main/java/nostr/event/BaseEvent.java index f343d9345..fcd148893 100644 --- a/nostr-java-event/src/main/java/nostr/event/BaseEvent.java +++ b/nostr-java-event/src/main/java/nostr/event/BaseEvent.java @@ -2,7 +2,6 @@ package nostr.event; import nostr.base.IEvent; -import nostr.base.PublicKey; import nostr.event.impl.GenericEvent; /** @@ -14,7 +13,6 @@ public abstract class BaseEvent implements IEvent { public static class ProxyEvent extends GenericEvent { public ProxyEvent(String id) { - super(new PublicKey(new byte[]{}), Kind.UNDEFINED); setId(id); } diff --git a/nostr-java-event/src/main/java/nostr/event/impl/EphemeralEvent.java b/nostr-java-event/src/main/java/nostr/event/impl/EphemeralEvent.java index 276a36356..407f22086 100644 --- a/nostr-java-event/src/main/java/nostr/event/impl/EphemeralEvent.java +++ b/nostr-java-event/src/main/java/nostr/event/impl/EphemeralEvent.java @@ -17,7 +17,7 @@ */ @Data @EqualsAndHashCode(callSuper = false) -@Event(name = "Ephemeral Events", nip = 1) +@Event(name = "Ephemeral Events") public class EphemeralEvent extends NIP01Event { public EphemeralEvent(PublicKey pubKey, Integer kind, List tags, String content) { diff --git a/nostr-java-event/src/main/java/nostr/event/impl/Filters.java b/nostr-java-event/src/main/java/nostr/event/impl/Filters.java index e36f5101a..c8d34538d 100644 --- a/nostr-java-event/src/main/java/nostr/event/impl/Filters.java +++ b/nostr-java-event/src/main/java/nostr/event/impl/Filters.java @@ -6,9 +6,11 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; import nostr.base.annotation.Key; import nostr.event.BaseEvent; import nostr.event.json.deserializer.CustomGenericTagQueryListDeserializer; @@ -26,6 +28,8 @@ @Builder @Data @EqualsAndHashCode(callSuper = false) +@NoArgsConstructor +@AllArgsConstructor public class Filters extends BaseEvent { @Key diff --git a/nostr-java-event/src/main/java/nostr/event/impl/InternetIdentifierMetadataEvent.java b/nostr-java-event/src/main/java/nostr/event/impl/InternetIdentifierMetadataEvent.java index 750a3bd71..179258a19 100644 --- a/nostr-java-event/src/main/java/nostr/event/impl/InternetIdentifierMetadataEvent.java +++ b/nostr-java-event/src/main/java/nostr/event/impl/InternetIdentifierMetadataEvent.java @@ -59,7 +59,7 @@ private void setContent(UserProfile profile) { @Data @AllArgsConstructor - public final class Nip05Obj{ + public static final class Nip05Obj{ private String name; private String nip05; } diff --git a/nostr-java-event/src/main/java/nostr/event/impl/ParameterizedReplaceableEvent.java b/nostr-java-event/src/main/java/nostr/event/impl/ParameterizedReplaceableEvent.java index faab4d17e..072bc8363 100644 --- a/nostr-java-event/src/main/java/nostr/event/impl/ParameterizedReplaceableEvent.java +++ b/nostr-java-event/src/main/java/nostr/event/impl/ParameterizedReplaceableEvent.java @@ -15,7 +15,7 @@ */ @Data @EqualsAndHashCode(callSuper = false) -@Event(name = "Parameterized Replaceable Events", nip = 1) +@Event(name = "Parameterized Replaceable Events") public class ParameterizedReplaceableEvent extends NIP01Event { protected ParameterizedReplaceableEvent() { diff --git a/nostr-java-event/src/main/java/nostr/event/impl/ReplaceableEvent.java b/nostr-java-event/src/main/java/nostr/event/impl/ReplaceableEvent.java index bea6c4b64..62a90d5ae 100644 --- a/nostr-java-event/src/main/java/nostr/event/impl/ReplaceableEvent.java +++ b/nostr-java-event/src/main/java/nostr/event/impl/ReplaceableEvent.java @@ -15,7 +15,7 @@ */ @Data @EqualsAndHashCode(callSuper = false) -@Event(name = "Replaceable Events", nip = 1) +@Event(name = "Replaceable Events") public class ReplaceableEvent extends NIP01Event { public ReplaceableEvent(PublicKey sender, Integer kind, List tags, String content) { diff --git a/nostr-java-event/src/main/java/nostr/event/json/codec/BaseMessageDecoder.java b/nostr-java-event/src/main/java/nostr/event/json/codec/BaseMessageDecoder.java index aea32dae1..efbc06de5 100644 --- a/nostr-java-event/src/main/java/nostr/event/json/codec/BaseMessageDecoder.java +++ b/nostr-java-event/src/main/java/nostr/event/json/codec/BaseMessageDecoder.java @@ -4,16 +4,15 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import java.util.Map; import lombok.AllArgsConstructor; import lombok.Data; import nostr.base.ElementAttribute; import nostr.base.IDecoder; import nostr.event.BaseMessage; import nostr.event.impl.ClientAuthenticationEvent; -import nostr.event.impl.Filters; import nostr.event.impl.GenericEvent; import nostr.event.impl.GenericMessage; +import nostr.event.list.FiltersList; import nostr.event.message.BaseAuthMessage; import nostr.event.message.ClientAuthenticationMessage; import nostr.event.message.CloseMessage; @@ -24,8 +23,9 @@ import nostr.event.message.RelayAuthenticationMessage; import nostr.event.message.ReqMessage; +import java.util.Map; + /** - * * @author eric */ @Data @@ -63,10 +63,8 @@ public BaseMessage decode() { } message = authMsg; } - case "CLOSE" -> - message = new CloseMessage(arg.toString()); - case "EOSE" -> - message = new EoseMessage(arg.toString()); + case "CLOSE" -> message = new CloseMessage(arg.toString()); + case "EOSE" -> message = new EoseMessage(arg.toString()); case "EVENT" -> { if (msgArr.length == 2 && arg instanceof Map map) { var event = mapper.convertValue(map, new TypeReference() { @@ -83,8 +81,7 @@ public BaseMessage decode() { throw new AssertionError("Invalid argument: " + arg); } } - case "NOTICE" -> - message = new NoticeMessage(arg.toString()); + case "NOTICE" -> message = new NoticeMessage(arg.toString()); case "OK" -> { if (msgArr.length == 4 && msgArr[2] instanceof Boolean duplicate) { String msgArg = msgArr[3].toString(); @@ -93,19 +90,13 @@ public BaseMessage decode() { throw new AssertionError("Invalid argument: " + msgArr[2]); } } - // TODO - Cater for more than one filters. Create issue in Github case "REQ" -> { - if (arg instanceof Map map) { - var filters = mapper.convertValue(map, new TypeReference() { - }); - message = new ReqMessage(arg.toString(), filters); - } else { - throw new AssertionError("Invalid argument: " + msgArr[2]); - } + var filtersList = mapper.convertValue(msgArr[2], new TypeReference() { + }); + message = new ReqMessage(arg.toString(), filtersList); } default -> { - //throw new AssertionError("Invalid command " + strCmd); - // NOTE: Only String attribute suppoeted. It would be impossible to guess the object's type + // NOTE: Only String attribute supported. It would be impossible to guess the object's type GenericMessage gm = new GenericMessage(strCmd); for (int i = 1; i < msgArr.length; i++) { if (msgArr[i] instanceof String) { diff --git a/nostr-java-event/src/main/java/nostr/event/json/codec/BaseMessageEncoder.java b/nostr-java-event/src/main/java/nostr/event/json/codec/BaseMessageEncoder.java index 21fb17c5c..bad25b72c 100644 --- a/nostr-java-event/src/main/java/nostr/event/json/codec/BaseMessageEncoder.java +++ b/nostr-java-event/src/main/java/nostr/event/json/codec/BaseMessageEncoder.java @@ -3,11 +3,12 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.JsonNodeFactory; import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NonNull; import nostr.base.IEncoder; -import static nostr.base.IEncoder.MAPPER; import nostr.base.Relay; import nostr.event.BaseEvent; import nostr.event.BaseMessage; @@ -20,7 +21,6 @@ import nostr.event.message.ReqMessage; /** - * * @author squirrel */ @Data @@ -29,7 +29,11 @@ public class BaseMessageEncoder implements IEncoder { private final BaseMessage message; private final Relay relay; - + + public BaseMessageEncoder(@NonNull BaseMessage message) { + this(message, null); + } + @Override public String encode() { var arrayNode = JsonNodeFactory.instance.arrayNode(); @@ -40,15 +44,26 @@ public String encode() { arrayNode.add(tree); } else if (message instanceof ReqMessage msg) { arrayNode.add(msg.getSubscriptionId()); - JsonNode tree = MAPPER.readTree(new BaseEventEncoder(msg.getFilters(), relay).encode()); - arrayNode.add(tree); + // Encode each filter individually and join them with a comma + ArrayNode filtersNode = JsonNodeFactory.instance.arrayNode(); + msg.getFiltersList().getList().stream() + .map(filter -> { + try { + return MAPPER.valueToTree(filter); + } catch (Exception e) { + throw new RuntimeException(e); + } + }) + .map(n -> ((JsonNode) n)) + .forEach(filtersNode::add); + arrayNode.add(filtersNode); } else if (message instanceof NoticeMessage msg) { arrayNode.add(msg.getMessage()); } else if (message instanceof CloseMessage msg) { arrayNode.add(msg.getSubscriptionId()); } else if (message instanceof ClientAuthenticationMessage msg) { arrayNode.add(msg.getEvent().toString()); - } else if (message instanceof RelayAuthenticationMessage msg){ + } else if (message instanceof RelayAuthenticationMessage msg) { arrayNode.add(msg.getChallenge()); } else if (message instanceof GenericMessage msg) { arrayNode.add(msg.getCommand()); diff --git a/nostr-java-event/src/main/java/nostr/event/json/codec/FiltersEncoder.java b/nostr-java-event/src/main/java/nostr/event/json/codec/FiltersEncoder.java index bc258263e..615867d45 100644 --- a/nostr-java-event/src/main/java/nostr/event/json/codec/FiltersEncoder.java +++ b/nostr-java-event/src/main/java/nostr/event/json/codec/FiltersEncoder.java @@ -1,20 +1,21 @@ package nostr.event.json.codec; import com.fasterxml.jackson.core.JsonProcessingException; -import java.util.Spliterator; -import java.util.Spliterators; -import java.util.stream.StreamSupport; - import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.Data; import lombok.EqualsAndHashCode; + import nostr.base.Relay; import nostr.event.impl.Filters; import nostr.util.NostrException; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.stream.StreamSupport; + /** * @author guilhermegps * diff --git a/nostr-java-event/src/main/java/nostr/event/json/codec/FiltersListDecoder.java b/nostr-java-event/src/main/java/nostr/event/json/codec/FiltersListDecoder.java new file mode 100644 index 000000000..7547a6ba2 --- /dev/null +++ b/nostr-java-event/src/main/java/nostr/event/json/codec/FiltersListDecoder.java @@ -0,0 +1,25 @@ +package nostr.event.json.codec; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.AllArgsConstructor; +import lombok.Data; +import nostr.base.IDecoder; +import nostr.event.list.FiltersList; + +@Data +@AllArgsConstructor +public class FiltersListDecoder implements IDecoder { + + private final String jsonString; + + @Override + public FiltersList decode() { + try { + ObjectMapper mapper = new ObjectMapper(); + return mapper.readValue(jsonString, FiltersList.class); + } catch (JsonProcessingException ex) { + throw new RuntimeException(ex); + } + } +} diff --git a/nostr-java-event/src/main/java/nostr/event/json/codec/FiltersListEncoder.java b/nostr-java-event/src/main/java/nostr/event/json/codec/FiltersListEncoder.java new file mode 100644 index 000000000..f79d38828 --- /dev/null +++ b/nostr-java-event/src/main/java/nostr/event/json/codec/FiltersListEncoder.java @@ -0,0 +1,69 @@ +package nostr.event.json.codec; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import lombok.Data; +import lombok.EqualsAndHashCode; +import nostr.base.Relay; +import nostr.event.BaseEvent; +import nostr.event.list.FiltersList; +import nostr.util.NostrException; + +@EqualsAndHashCode(callSuper = true) +@Data +public class FiltersListEncoder extends BaseEventEncoder { + + private final FiltersList filtersList; + private boolean arrayFlag; + + public FiltersListEncoder(FiltersList filtersList, Relay relay) { + super(null, relay); + this.filtersList = filtersList; + this.arrayFlag = false; + } + + public FiltersListEncoder(FiltersList filtersList) { + super(null); + this.filtersList = filtersList; + this.arrayFlag = false; + } + + @Override + public BaseEvent getEvent() { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + protected String toJson() throws NostrException { + if (arrayFlag) { + return toJsonArray(); + } else { + return toJsonCommaSeparated(); + } + } + + private String toJsonArray() throws NostrException { + try { + StringBuilder sb = new StringBuilder(); + for (Object filter : getFiltersList().getList()) { + if (!sb.isEmpty()) { + sb.append(","); + } + sb.append(MAPPER.writeValueAsString(filter)); + } + return sb.toString(); + } catch (JsonProcessingException | IllegalArgumentException e) { + throw new NostrException(e); + } + } + + private String toJsonCommaSeparated() throws NostrException { + JsonNode node = MAPPER.valueToTree(getFiltersList().getList()); + try { + return MAPPER.writeValueAsString(node); + } catch (JsonProcessingException e) { + throw new NostrException(e); + } + + } +} diff --git a/nostr-java-event/src/main/java/nostr/event/json/deserializer/CustomEventListDeserializer.java b/nostr-java-event/src/main/java/nostr/event/json/deserializer/CustomEventListDeserializer.java new file mode 100644 index 000000000..cb8f53ee5 --- /dev/null +++ b/nostr-java-event/src/main/java/nostr/event/json/deserializer/CustomEventListDeserializer.java @@ -0,0 +1,26 @@ +package nostr.event.json.deserializer; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; +import nostr.event.json.codec.GenericEventDecoder; +import nostr.event.list.EventList; + +import java.io.IOException; + +public class CustomEventListDeserializer extends JsonDeserializer { + + @Override + public EventList deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException { + EventList eventList = new EventList(); + JsonNode node = jsonParser.readValueAsTree(); + if (node.isArray()) { + for (JsonNode n : node) { + GenericEventDecoder decoder = new GenericEventDecoder(n.toString()); + eventList.add(decoder.decode()); + } + } + return eventList; + } +} diff --git a/nostr-java-event/src/main/java/nostr/event/json/deserializer/CustomFiltersListDeserializer.java b/nostr-java-event/src/main/java/nostr/event/json/deserializer/CustomFiltersListDeserializer.java new file mode 100644 index 000000000..a3d0cf13c --- /dev/null +++ b/nostr-java-event/src/main/java/nostr/event/json/deserializer/CustomFiltersListDeserializer.java @@ -0,0 +1,44 @@ +package nostr.event.json.deserializer; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.NonNull; +import nostr.event.json.codec.FiltersDecoder; +import nostr.event.list.FiltersList; + +import java.io.IOException; +import java.util.Iterator; + +public class CustomFiltersListDeserializer extends JsonDeserializer { + + @Override + public FiltersList deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException { + JsonNode node = jsonParser.readValueAsTree(); + return parseJson(node.toString()); + } + + public static FiltersList parseJson(@NonNull String jsonString) throws IOException { + if (!jsonString.startsWith("[")) { + jsonString = "[" + jsonString.trim(); + } + if (!jsonString.endsWith("]")) { + jsonString = jsonString + "]"; + } + + FiltersList filtersList = new FiltersList(); + ObjectMapper mapper = new ObjectMapper(); + JsonNode rootNode = mapper.readTree(jsonString); + Iterator elementsIterator = rootNode.elements(); + while (elementsIterator.hasNext()) { + JsonNode element = elementsIterator.next(); + String strFilters = element.toString(); + FiltersDecoder decoder = new FiltersDecoder(strFilters); + filtersList.add(decoder.decode()); + } + + return filtersList; + } +} diff --git a/nostr-java-event/src/main/java/nostr/event/json/deserializer/CustomKindListDeserializer.java b/nostr-java-event/src/main/java/nostr/event/json/deserializer/CustomKindListDeserializer.java new file mode 100644 index 000000000..53ca185f7 --- /dev/null +++ b/nostr-java-event/src/main/java/nostr/event/json/deserializer/CustomKindListDeserializer.java @@ -0,0 +1,24 @@ +package nostr.event.json.deserializer; + +import com.fasterxml.jackson.core.JacksonException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; +import nostr.event.list.KindList; + +import java.io.IOException; + +public class CustomKindListDeserializer extends JsonDeserializer { + @Override + public KindList deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException { + KindList kindList = new KindList(); + JsonNode node = jsonParser.readValueAsTree(); + if (node.isArray()) { + for (JsonNode n : node) { + kindList.add(Integer.decode(n.asText())); + } + } + return kindList; + } +} diff --git a/nostr-java-event/src/main/java/nostr/event/json/deserializer/CustomPublicKeyListDeserializer.java b/nostr-java-event/src/main/java/nostr/event/json/deserializer/CustomPublicKeyListDeserializer.java new file mode 100644 index 000000000..0e36e86eb --- /dev/null +++ b/nostr-java-event/src/main/java/nostr/event/json/deserializer/CustomPublicKeyListDeserializer.java @@ -0,0 +1,26 @@ +package nostr.event.json.deserializer; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; +import nostr.base.PublicKey; +import nostr.event.list.PublicKeyList; + +import java.io.IOException; + +public class CustomPublicKeyListDeserializer extends JsonDeserializer { + + @Override + public PublicKeyList deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + PublicKeyList publicKeyList = new PublicKeyList(); + JsonNode node = p.readValueAsTree(); + if (node.isArray()) { + for (JsonNode n : node) { + String hex = n.asText(); + publicKeyList.add(new PublicKey(hex)); + } + } + return publicKeyList; + } +} diff --git a/nostr-java-event/src/main/java/nostr/event/list/BaseList.java b/nostr-java-event/src/main/java/nostr/event/list/BaseList.java index 054c9d44c..cddf901c6 100644 --- a/nostr-java-event/src/main/java/nostr/event/list/BaseList.java +++ b/nostr-java-event/src/main/java/nostr/event/list/BaseList.java @@ -1,15 +1,14 @@ package nostr.event.list; -import java.util.List; - import com.fasterxml.jackson.databind.annotation.JsonSerialize; - import lombok.AllArgsConstructor; import lombok.Data; import lombok.NonNull; import nostr.base.INostrList; import nostr.event.json.serializer.CustomBaseListSerializer; +import java.util.List; + /** * * @author squirrel @@ -24,6 +23,10 @@ public abstract class BaseList implements INostrList { @NonNull private final List list; + public BaseList(T... elements) { + this.list = List.of(elements); + } + @Override public void add(@NonNull T elt) { if (!list.contains(elt)) { diff --git a/nostr-java-event/src/main/java/nostr/event/list/EventList.java b/nostr-java-event/src/main/java/nostr/event/list/EventList.java index a0808bf55..b869e2d52 100644 --- a/nostr-java-event/src/main/java/nostr/event/list/EventList.java +++ b/nostr-java-event/src/main/java/nostr/event/list/EventList.java @@ -1,12 +1,14 @@ package nostr.event.list; -import java.util.ArrayList; -import java.util.List; - +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import lombok.Builder; import lombok.NonNull; import nostr.event.impl.GenericEvent; +import nostr.event.json.deserializer.CustomEventListDeserializer; + +import java.util.ArrayList; +import java.util.List; /** * @@ -14,12 +16,17 @@ */ @Builder // TODO - public class EventList extends BaseList +@JsonDeserialize(using = CustomEventListDeserializer.class) public class EventList extends BaseList { public EventList() { this(new ArrayList<>()); } + public EventList(GenericEvent... events) { + super(events); + } + private EventList(@NonNull List list) { super(list); } diff --git a/nostr-java-event/src/main/java/nostr/event/list/FiltersList.java b/nostr-java-event/src/main/java/nostr/event/list/FiltersList.java index cbf0bbb3d..817a42591 100644 --- a/nostr-java-event/src/main/java/nostr/event/list/FiltersList.java +++ b/nostr-java-event/src/main/java/nostr/event/list/FiltersList.java @@ -1,24 +1,32 @@ package nostr.event.list; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import lombok.Builder; +import lombok.NonNull; import nostr.event.impl.Filters; +import nostr.event.json.deserializer.CustomFiltersListDeserializer; + import java.util.ArrayList; import java.util.List; -import lombok.Builder; -import lombok.NonNull; /** * * @author squirrel */ @Builder +@JsonDeserialize(using = CustomFiltersListDeserializer.class) public class FiltersList extends BaseList { public FiltersList() { this(new ArrayList<>()); } - private FiltersList(@NonNull List list) { + public FiltersList(Filters... filters) { + super(filters); + } + + public FiltersList(@NonNull List list) { super(list); } } diff --git a/nostr-java-event/src/main/java/nostr/event/list/GenericTagQueryList.java b/nostr-java-event/src/main/java/nostr/event/list/GenericTagQueryList.java index 6272e091e..844fe7250 100644 --- a/nostr-java-event/src/main/java/nostr/event/list/GenericTagQueryList.java +++ b/nostr-java-event/src/main/java/nostr/event/list/GenericTagQueryList.java @@ -1,12 +1,12 @@ package nostr.event.list; -import java.util.ArrayList; -import java.util.List; - import lombok.Builder; import lombok.NonNull; import nostr.base.GenericTagQuery; +import java.util.ArrayList; +import java.util.List; + /** * * @author squirrel @@ -18,6 +18,10 @@ public GenericTagQueryList() { this(new ArrayList<>()); } + public GenericTagQueryList(GenericTagQuery... queries) { + super(queries); + } + private GenericTagQueryList(@NonNull List list) { super(list); } diff --git a/nostr-java-event/src/main/java/nostr/event/list/KindList.java b/nostr-java-event/src/main/java/nostr/event/list/KindList.java index 6459a1547..d2680b67c 100644 --- a/nostr-java-event/src/main/java/nostr/event/list/KindList.java +++ b/nostr-java-event/src/main/java/nostr/event/list/KindList.java @@ -1,23 +1,30 @@ package nostr.event.list; -import java.util.ArrayList; -import java.util.List; - +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import lombok.Builder; import lombok.NonNull; +import nostr.event.json.deserializer.CustomKindListDeserializer; + +import java.util.ArrayList; +import java.util.List; /** * * @author squirrel */ @Builder +@JsonDeserialize(using = CustomKindListDeserializer.class) public class KindList extends BaseList { public KindList() { this(new ArrayList<>()); } + public KindList(Integer... kinds) { + super(kinds); + } + public KindList(@NonNull List list) { super(new ArrayList<>(list)); } diff --git a/nostr-java-event/src/main/java/nostr/event/list/PublicKeyList.java b/nostr-java-event/src/main/java/nostr/event/list/PublicKeyList.java index 47ed63f86..9b67a803c 100644 --- a/nostr-java-event/src/main/java/nostr/event/list/PublicKeyList.java +++ b/nostr-java-event/src/main/java/nostr/event/list/PublicKeyList.java @@ -1,24 +1,31 @@ package nostr.event.list; -import java.util.ArrayList; -import java.util.List; - +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import lombok.Builder; import lombok.NonNull; import nostr.base.PublicKey; +import nostr.event.json.deserializer.CustomPublicKeyListDeserializer; + +import java.util.ArrayList; +import java.util.List; /** * * @author squirrel */ @Builder +@JsonDeserialize(using = CustomPublicKeyListDeserializer.class) public class PublicKeyList extends BaseList { public PublicKeyList() { this(new ArrayList<>()); } + public PublicKeyList(PublicKey... publicKeys) { + super(publicKeys); + } + public PublicKeyList(@NonNull List list) { super(new ArrayList<>(list)); } diff --git a/nostr-java-event/src/main/java/nostr/event/message/ReqMessage.java b/nostr-java-event/src/main/java/nostr/event/message/ReqMessage.java index 8684cdc67..33b8bed09 100644 --- a/nostr-java-event/src/main/java/nostr/event/message/ReqMessage.java +++ b/nostr-java-event/src/main/java/nostr/event/message/ReqMessage.java @@ -8,6 +8,7 @@ import nostr.base.Command; import nostr.event.BaseMessage; import nostr.event.impl.Filters; +import nostr.event.list.FiltersList; /** * @@ -22,11 +23,18 @@ public class ReqMessage extends BaseMessage { private final String subscriptionId; @JsonProperty - private final Filters filters; + private final FiltersList filtersList; public ReqMessage(String subscriptionId, Filters filters) { super(Command.REQ.name()); this.subscriptionId = subscriptionId; - this.filters = filters; + this.filtersList = new FiltersList(); + this.filtersList.add(filters); + } + + public ReqMessage(String subscriptionId, FiltersList filtersList) { + super(Command.REQ.name()); + this.subscriptionId = subscriptionId; + this.filtersList = filtersList; } } diff --git a/nostr-java-event/src/main/java/nostr/event/util/Nip05Validator.java b/nostr-java-event/src/main/java/nostr/event/util/Nip05Validator.java index 712b53c00..4c81c3df7 100644 --- a/nostr-java-event/src/main/java/nostr/event/util/Nip05Validator.java +++ b/nostr-java-event/src/main/java/nostr/event/util/Nip05Validator.java @@ -1,5 +1,13 @@ package nostr.event.util; +import lombok.Builder; +import lombok.Data; +import lombok.extern.java.Log; +import nostr.base.PublicKey; +import nostr.event.Nip05Content; +import nostr.event.json.codec.Nip05ContentDecoder; +import nostr.util.NostrException; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @@ -10,14 +18,6 @@ import java.util.Map; import java.util.logging.Level; -import lombok.Builder; -import lombok.Data; -import lombok.extern.java.Log; -import nostr.base.PublicKey; -import nostr.event.Nip05Content; -import nostr.event.json.codec.Nip05ContentDecoder; -import nostr.util.NostrException; - /** * * @author squirrel diff --git a/nostr-java-examples/src/main/java/nostr/examples/NostrApiExamples.java b/nostr-java-examples/src/main/java/nostr/examples/NostrApiExamples.java index 680685e04..450186a56 100644 --- a/nostr-java-examples/src/main/java/nostr/examples/NostrApiExamples.java +++ b/nostr-java-examples/src/main/java/nostr/examples/NostrApiExamples.java @@ -151,7 +151,7 @@ public static void main(String[] args) throws Exception { executor.submit(() -> { try { filters(); - } catch(Throwable t) { log.log(Level.SEVERE, t.getMessage(), t); }; + } catch(Throwable t) { log.log(Level.SEVERE, t.getMessage(), t); } }); // // executor.submit(() -> { @@ -378,14 +378,14 @@ private static GenericEvent muteUser() { private static void logAccountsData() { String msg = "################################ ACCOUNTS BEGINNING ################################" + '\n' + "*** RECEIVER ***" + '\n' + - '\n' + "* PrivateKey: " + RECIPIENT.getPrivateKey().getBech32() + + '\n' + "* PrivateKey: " + RECIPIENT.getPrivateKey().toBech32String() + '\n' + "* PrivateKey HEX: " + RECIPIENT.getPrivateKey().toString() + - '\n' + "* PublicKey: " + RECIPIENT.getPublicKey().getBech32() + + '\n' + "* PublicKey: " + RECIPIENT.getPublicKey().toBech32String() + '\n' + "* PublicKey HEX: " + RECIPIENT.getPublicKey().toString() + '\n' + '\n' + "*** SENDER ***" + '\n' + - '\n' + "* PrivateKey: " + SENDER.getPrivateKey().getBech32() + + '\n' + "* PrivateKey: " + SENDER.getPrivateKey().toBech32String() + '\n' + "* PrivateKey HEX: " + SENDER.getPrivateKey().toString() + - '\n' + "* PublicKey: " + SENDER.getPublicKey().getBech32() + + '\n' + "* PublicKey: " + SENDER.getPublicKey().toBech32String() + '\n' + "* PublicKey HEX: " + SENDER.getPublicKey().toString() + '\n' + '\n' + "################################ ACCOUNTS END ################################"; diff --git a/nostr-java-test/src/test/java/nostr/test/event/ApiEventTest.java b/nostr-java-test/src/test/java/nostr/test/event/ApiEventTest.java index e0fecbae2..bb830b0ed 100644 --- a/nostr-java-test/src/test/java/nostr/test/event/ApiEventTest.java +++ b/nostr-java-test/src/test/java/nostr/test/event/ApiEventTest.java @@ -101,7 +101,7 @@ public void testNIP44SendDirectMessage() { } @Test - public void testNIP04EncryptDecrypt() throws NostrException { + public void testNIP04EncryptDecrypt() { System.out.println("testNIP04EncryptDecrypt"); var nostr_java = new PublicKey(NOSTR_JAVA_PUBKEY); @@ -202,8 +202,8 @@ public void testNIP15UpdateProductEvent() { categories.add("bijoux"); categories.add("Hommes"); - var instance = nip15.createCreateOrUpdateProductEvent(product, categories); - nip15.sign().send(); + nip15.createCreateOrUpdateProductEvent(product, categories).sign().send(); + //nip15.sign().send(); product.setDescription("Un nouveau bijou en or"); categories.add("bagues"); diff --git a/nostr-java-test/src/test/java/nostr/test/event/DecodeTest.java b/nostr-java-test/src/test/java/nostr/test/event/DecodeTest.java index 141fe666a..b5c7f6184 100644 --- a/nostr-java-test/src/test/java/nostr/test/event/DecodeTest.java +++ b/nostr-java-test/src/test/java/nostr/test/event/DecodeTest.java @@ -1,6 +1,7 @@ package nostr.test.event; import nostr.base.PublicKey; +import nostr.event.BaseMessage; import nostr.event.BaseTag; import nostr.event.Marker; import nostr.event.impl.GenericEvent; @@ -13,7 +14,6 @@ import java.util.ArrayList; import java.util.List; -import nostr.event.BaseMessage; public class DecodeTest { diff --git a/nostr-java-test/src/test/java/nostr/test/json/JsonParseTest.java b/nostr-java-test/src/test/java/nostr/test/json/JsonParseTest.java index 71a561573..66a59ace6 100644 --- a/nostr-java-test/src/test/java/nostr/test/json/JsonParseTest.java +++ b/nostr-java-test/src/test/java/nostr/test/json/JsonParseTest.java @@ -4,30 +4,88 @@ import nostr.base.ElementAttribute; import nostr.base.PublicKey; import nostr.crypto.bech32.Bech32; +import nostr.event.BaseEvent; import nostr.event.BaseMessage; import nostr.event.BaseTag; import nostr.event.Marker; +import nostr.event.impl.Filters; import nostr.event.impl.GenericEvent; import nostr.event.impl.GenericTag; import nostr.event.json.codec.BaseMessageDecoder; -import nostr.event.json.codec.GenericTagDecoder; +import nostr.event.json.codec.BaseMessageEncoder; import nostr.event.json.codec.BaseTagDecoder; +import nostr.event.json.codec.GenericTagDecoder; +import nostr.event.list.EventList; +import nostr.event.list.FiltersList; +import nostr.event.list.KindList; +import nostr.event.list.PublicKeyList; import nostr.event.message.EventMessage; +import nostr.event.message.ReqMessage; import nostr.event.tag.EventTag; import nostr.event.tag.PubKeyTag; +import nostr.id.Identity; import nostr.util.NostrException; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** - * * @author eric */ public class JsonParseTest { @Test - public void testBaseMessageDecoder() { - System.out.println("testBaseMessageDecoder"); + public void testBaseReqMessageDecoder() { + System.out.println("testBaseReqMessageDecoder"); + + final String parseTarget = + "[\"REQ\", " + + "\"npub17x6pn22ukq3n5yw5x9prksdyyu6ww9jle2ckpqwdprh3ey8qhe6stnpujh\", " + + "{\"kinds\": [1], " + + "\"authors\": [\"f1b419a95cb0233a11d431423b41a42734e7165fcab16081cd08ef1c90e0be75\"]," + + "\"#e\": [\"fc7f200c5bed175702bd06c7ca5dba90d3497e827350b42fc99c3a4fa276a712\"]}]"; + + final var message = new BaseMessageDecoder(parseTarget).decode(); + + Assertions.assertEquals(Command.REQ.toString(), message.getCommand()); + Assertions.assertEquals("npub17x6pn22ukq3n5yw5x9prksdyyu6ww9jle2ckpqwdprh3ey8qhe6stnpujh", ((ReqMessage) message).getSubscriptionId()); + Assertions.assertEquals(1, ((ReqMessage) message).getFiltersList().size()); + + var filters = ((ReqMessage) message).getFiltersList().getList().get(0); + + Assertions.assertEquals(1, filters.getKinds().size()); + Assertions.assertEquals(1, filters.getKinds().getList().get(0).intValue()); + + Assertions.assertEquals(1, filters.getAuthors().size()); + Assertions.assertEquals("npub17x6pn22ukq3n5yw5x9prksdyyu6ww9jle2ckpqwdprh3ey8qhe6stnpujh", filters.getAuthors().getList().get(0).toBech32String()); + + Assertions.assertEquals(1, filters.getReferencedEvents().size()); + Assertions.assertEquals("fc7f200c5bed175702bd06c7ca5dba90d3497e827350b42fc99c3a4fa276a712", filters.getReferencedEvents().getList().get(0).getId()); + } + + @Test + public void testBaseReqMessageEncoder() { + System.out.println("testBaseReqMessageEncoder"); + + final var filtersList = new FiltersList(); + var publicKey = Identity.generateRandomIdentity().getPublicKey(); + filtersList.add(Filters.builder().authors(new PublicKeyList(publicKey)).kinds(new KindList(3,5)).build()); + filtersList.add(Filters.builder().kinds(new KindList(0,1)).build()); + filtersList.add(Filters.builder().referencedEvents(new EventList(new BaseEvent.ProxyEvent("fc7f200c5bed175702bd06c7ca5dba90d3497e827350b42fc99c3a4fa276a712"))).build()); + + final var reqMessage = new ReqMessage(publicKey.toString(), filtersList); + + BaseMessageEncoder encoder = new BaseMessageEncoder(reqMessage); + + var jsonMessage = encoder.encode(); + + var message = new BaseMessageDecoder(jsonMessage).decode(); + + Assertions.assertEquals(reqMessage, message); + } + + @Test + public void testBaseEventMessageDecoder() { + System.out.println("testBaseEventMessageDecoder"); final String parseTarget = "[\"EVENT\"," @@ -54,8 +112,8 @@ public void testBaseMessageDecoder() { } @Test - public void testBaseMessageMarkerDecoder() { - System.out.println("testBaseMessageMarkerDecoder"); + public void testBaseEventMessageMarkerDecoder() { + System.out.println("testBaseEventMessageMarkerDecoder"); String json = "[" + "\"EVENT\"," diff --git a/nostr-java-ws-handler-command-provider/src/main/java/nostr/ws/handler/command/provider/DefaultCommandHandler.java b/nostr-java-ws-handler-command-provider/src/main/java/nostr/ws/handler/command/provider/DefaultCommandHandler.java index f31ddcf5b..91dd41bed 100644 --- a/nostr-java-ws-handler-command-provider/src/main/java/nostr/ws/handler/command/provider/DefaultCommandHandler.java +++ b/nostr-java-ws-handler-command-provider/src/main/java/nostr/ws/handler/command/provider/DefaultCommandHandler.java @@ -44,7 +44,7 @@ public void onEvent(String jsonEvent, String subId, Relay relay) { } @Override - public void onAuth(String challenge, Relay relay) throws NostrException { + public void onAuth(String challenge, Relay relay) { log.log(Level.FINE, "Command: {0} - Relay {1}", new Object[]{Command.AUTH, relay}); var client = Client.getInstance(); diff --git a/nostr-java-ws-handler-interface/src/main/java/nostr/ws/handler/command/spi/ICommandHandler.java b/nostr-java-ws-handler-interface/src/main/java/nostr/ws/handler/command/spi/ICommandHandler.java index a5a27b32b..0304c5208 100644 --- a/nostr-java-ws-handler-interface/src/main/java/nostr/ws/handler/command/spi/ICommandHandler.java +++ b/nostr-java-ws-handler-interface/src/main/java/nostr/ws/handler/command/spi/ICommandHandler.java @@ -4,11 +4,11 @@ */ package nostr.ws.handler.command.spi; -import java.util.Arrays; -import java.util.Optional; import nostr.base.IHandler; import nostr.base.Relay; -import nostr.util.NostrException; + +import java.util.Arrays; +import java.util.Optional; /** * @@ -24,7 +24,7 @@ public interface ICommandHandler extends IHandler { void onEvent(String jsonEvent, String subId, Relay relay); - void onAuth(String challenge, Relay relay) throws NostrException; + void onAuth(String challenge, Relay relay); enum Reason { UNDEFINED(""), From b8c401f89330464d4a8c9ab885d822017f81d615 Mon Sep 17 00:00:00 2001 From: erict875 Date: Sat, 23 Mar 2024 01:32:27 +0000 Subject: [PATCH 2/3] Added the Nostr Public Channel id. --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6a3eec994..b62e7308a 100644 --- a/README.md +++ b/README.md @@ -39,9 +39,12 @@ The following NIPs are supported by the API out-of-the-box: - [NIP-57](https://github.com/nostr-protocol/nips/blob/master/57.md) We also provide the classes [GenericEvent](https://github.com/tcheeric/nostr-java/blob/main/nostr-java-event/src/main/java/nostr/event/impl/GenericEvent.java) and [GenericTag](https://github.com/tcheeric/nostr-java/blob/main/nostr-java-event/src/main/java/nostr/event/impl/GenericTag.java) for creating events and tags that are currently not supported out-of-the-box. -See working example [here](https://github.com/tcheeric/nostr-java/tree/main/nostr-java-examples) +See a working example [here](https://github.com/tcheeric/nostr-java/tree/main/nostr-java-examples) Additional reading: - [nostr-java-api](https://github.com/tcheeric/nostr-java/tree/main/nostr-java-api) - [nostr-java-id](https://github.com/tcheeric/nostr-java/tree/main/nostr-java-id) - [nostr-java-examples](https://github.com/tcheeric/nostr-java/tree/main/nostr-java-examples) + +## Dev Discussion Group: +- Nostr Public Channel: nostr:nevent1qqszqdmxg26sehmnyrcu2ler8azz6wyj6fh0qg3ad5fnnm6xfqqvhzcppamhxue69uhkummnw3ezumt0d5pzpl7nwh45p66gvet2q28dhjpcyh6clux4cjsm5gh7waza9pzjnmgglv06ew From 8f86c8705d79d5cc32cf4339e8bb4d81438ff213 Mon Sep 17 00:00:00 2001 From: erict875 Date: Sat, 23 Mar 2024 01:42:42 +0000 Subject: [PATCH 3/3] Added the Nostr Public Channel id. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index b62e7308a..1866f4869 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,6 @@ The following NIPs are supported by the API out-of-the-box: - [NIP-30](https://github.com/nostr-protocol/nips/blob/master/30.md) - [NIP-32](https://github.com/nostr-protocol/nips/blob/master/32.md) - [NIP-40](https://github.com/nostr-protocol/nips/blob/master/40.md) -- [NIP-42](https://github.com/nostr-protocol/nips/blob/master/42.md) - [NIP-44](https://github.com/nostr-protocol/nips/blob/master/44.md) - [NIP-46](https://github.com/nostr-protocol/nips/blob/master/46.md) - [NIP-57](https://github.com/nostr-protocol/nips/blob/master/57.md)