From acf426ccdc4d8462cbee83b85c5e9fe21b329a73 Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Wed, 18 Jun 2025 13:28:43 -0300 Subject: [PATCH] Add a UnsignedEventDeserializer --- .../quartz/nip01Core/jackson/EventMapper.kt | 3 +- .../jackson/UnsignedEventDeserializer.kt | 33 +++++++++++ .../UnsignedEventManualDeserializer.kt | 43 ++++++++++++++ .../jackson/EventDeserializerTest.kt | 56 +++++++++++++++++++ 4 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/jackson/UnsignedEventDeserializer.kt create mode 100644 quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/jackson/UnsignedEventManualDeserializer.kt create mode 100644 quartz/src/test/java/com/vitorpamplona/quartz/nip01Core/jackson/EventDeserializerTest.kt diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/jackson/EventMapper.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/jackson/EventMapper.kt index 9794d9bb9..f99a3e665 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/jackson/EventMapper.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/jackson/EventMapper.kt @@ -60,7 +60,8 @@ class EventMapper { .addSerializer(BunkerRequest::class.java, BunkerRequest.BunkerRequestSerializer()) .addDeserializer(BunkerRequest::class.java, BunkerRequest.BunkerRequestDeserializer()) .addSerializer(BunkerResponse::class.java, BunkerResponse.BunkerResponseSerializer()) - .addDeserializer(BunkerResponse::class.java, BunkerResponse.BunkerResponseDeserializer()), + .addDeserializer(BunkerResponse::class.java, BunkerResponse.BunkerResponseDeserializer()) + .addDeserializer(Event::class.java, UnsignedEventDeserializer()), ) fun fromJson(json: String): Event = mapper.readValue(json, Event::class.java) diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/jackson/UnsignedEventDeserializer.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/jackson/UnsignedEventDeserializer.kt new file mode 100644 index 000000000..af118db2d --- /dev/null +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/jackson/UnsignedEventDeserializer.kt @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip01Core.jackson + +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.deser.std.StdDeserializer +import com.vitorpamplona.quartz.nip01Core.core.Event + +class UnsignedEventDeserializer : StdDeserializer(Event::class.java) { + override fun deserialize( + jp: JsonParser, + ctxt: DeserializationContext, + ): Event = UnsignedEventManualDeserializer.fromJson(jp.codec.readTree(jp)) +} diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/jackson/UnsignedEventManualDeserializer.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/jackson/UnsignedEventManualDeserializer.kt new file mode 100644 index 000000000..8d3b4528c --- /dev/null +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/jackson/UnsignedEventManualDeserializer.kt @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip01Core.jackson + +import com.fasterxml.jackson.databind.JsonNode +import com.vitorpamplona.quartz.EventFactory +import com.vitorpamplona.quartz.nip01Core.core.Event + +class UnsignedEventManualDeserializer { + companion object { + fun fromJson(jsonObject: JsonNode): Event = + EventFactory.create( + id = jsonObject.get("id")?.asText()?.intern() ?: "", + pubKey = jsonObject.get("pubkey")?.asText()?.intern() ?: "", + createdAt = jsonObject.get("created_at").asLong(), + kind = jsonObject.get("kind").asInt(), + tags = + jsonObject.get("tags").toTypedArray { + it.toTypedArray { s -> if (s.isNull) "" else s.asText().intern() } + }, + content = jsonObject.get("content").asText(), + sig = jsonObject.get("sig")?.asText()?.intern() ?: "", + ) + } +} diff --git a/quartz/src/test/java/com/vitorpamplona/quartz/nip01Core/jackson/EventDeserializerTest.kt b/quartz/src/test/java/com/vitorpamplona/quartz/nip01Core/jackson/EventDeserializerTest.kt new file mode 100644 index 000000000..d591b4baa --- /dev/null +++ b/quartz/src/test/java/com/vitorpamplona/quartz/nip01Core/jackson/EventDeserializerTest.kt @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip01Core.jackson + +import com.vitorpamplona.quartz.nip01Core.core.Event +import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair +import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal +import com.vitorpamplona.quartz.nip01Core.verify +import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent +import org.junit.Test + +class EventDeserializerTest { + @Test + fun testUnsignedEvent() { + val unsignedEventJson = """{"kind":"1","content":"This is an unsigned event.","created_at":1234,"tags":[]}""" + val event = Event.fromJson(unsignedEventJson) + assert(event.id.isEmpty()) + assert(event.pubKey.isEmpty()) + assert(event.sig.isEmpty()) + assert(!event.verify()) + } + + @Test + fun testSignedEvent() { + val keyPair = KeyPair() + val signer = NostrSignerInternal(keyPair) + + val unsignedEvent = TextNoteEvent.build("test") + val signedEvent = signer.signerSync.sign(unsignedEvent)!! + val eventJson = signedEvent.toJson() + val event = Event.fromJson(eventJson) + + assert(event.id.isNotEmpty()) + assert(event.sig.isNotEmpty()) + assert(event.pubKey.isNotEmpty()) + assert(event.verify()) + } +}