mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-04-11 13:32:03 +02:00
Adds basic support for NIP-46 events.
This commit is contained in:
parent
7d9efcd1d9
commit
b5709f9527
@ -0,0 +1,254 @@
|
||||
/**
|
||||
* Copyright (c) 2024 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.events.nip46
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.vitorpamplona.quartz.crypto.KeyPair
|
||||
import com.vitorpamplona.quartz.events.ContactListEvent
|
||||
import com.vitorpamplona.quartz.events.Event
|
||||
import com.vitorpamplona.quartz.signers.NostrSignerInternal
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
import junit.framework.TestCase.assertEquals
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
internal class Nip46Test {
|
||||
val remoteKey = NostrSignerInternal(KeyPair())
|
||||
val signer = NostrSignerInternal(KeyPair())
|
||||
val peer = NostrSignerInternal(KeyPair())
|
||||
|
||||
val dummyEvent =
|
||||
Event(
|
||||
id = "",
|
||||
pubKey = "",
|
||||
createdAt = TimeUtils.now(),
|
||||
kind = 1,
|
||||
tags = emptyArray(),
|
||||
content = "test",
|
||||
sig = "",
|
||||
)
|
||||
|
||||
fun <T : BunkerMessage> encodeDecodeEvent(req: T): T {
|
||||
var countDownLatch = CountDownLatch(1)
|
||||
var eventStr: String? = null
|
||||
|
||||
NostrConnectEvent.create(req, remoteKey.pubKey, signer) {
|
||||
eventStr = it.toJson()
|
||||
countDownLatch.countDown()
|
||||
}
|
||||
|
||||
countDownLatch.await()
|
||||
|
||||
countDownLatch = CountDownLatch(1)
|
||||
var innerMessage: T? = null
|
||||
|
||||
(Event.fromJson(eventStr!!) as NostrConnectEvent).plainContent(signer) {
|
||||
innerMessage = it as T
|
||||
countDownLatch.countDown()
|
||||
}
|
||||
|
||||
countDownLatch.await()
|
||||
|
||||
return innerMessage!!
|
||||
}
|
||||
|
||||
@Test
|
||||
fun signEncoder() {
|
||||
val expected = BunkerRequestSign(event = dummyEvent)
|
||||
val actual = encodeDecodeEvent(expected)
|
||||
|
||||
assertEquals(BunkerRequestSign.METHOD_NAME, actual.method)
|
||||
assertEquals(expected.id, actual.id)
|
||||
assertEquals(dummyEvent.id, actual.event.id)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectEncoder() {
|
||||
val expected = BunkerRequestConnect(remoteKey = remoteKey.pubKey)
|
||||
val actual = encodeDecodeEvent(expected)
|
||||
|
||||
assertEquals(expected.method, actual.method)
|
||||
assertEquals(expected.id, actual.id)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun pingEncoder() {
|
||||
val expected = BunkerRequestPing()
|
||||
val actual = encodeDecodeEvent(expected)
|
||||
|
||||
assertEquals(expected.method, actual.method)
|
||||
assertEquals(expected.id, actual.id)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getPubkeyEncoder() {
|
||||
val expected = BunkerRequestGetPublicKey()
|
||||
val actual = encodeDecodeEvent(expected)
|
||||
|
||||
assertEquals(expected.method, actual.method)
|
||||
assertEquals(expected.id, actual.id)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getRelaysEncoder() {
|
||||
val expected = BunkerRequestGetRelays()
|
||||
val actual = encodeDecodeEvent(expected)
|
||||
|
||||
assertEquals(expected.method, actual.method)
|
||||
assertEquals(expected.id, actual.id)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNip04Encrypt() {
|
||||
val expected = BunkerRequestNip04Encrypt(pubKey = peer.pubKey, message = "Test")
|
||||
val actual = encodeDecodeEvent(expected)
|
||||
|
||||
assertEquals(expected.method, actual.method)
|
||||
assertEquals(expected.id, actual.id)
|
||||
assertEquals(expected.pubKey, actual.pubKey)
|
||||
assertEquals(expected.message, actual.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNip44Encrypt() {
|
||||
val expected = BunkerRequestNip44Encrypt(pubKey = peer.pubKey, message = "Test")
|
||||
val actual = encodeDecodeEvent(expected)
|
||||
|
||||
assertEquals(expected.method, actual.method)
|
||||
assertEquals(expected.id, actual.id)
|
||||
assertEquals(expected.pubKey, actual.pubKey)
|
||||
assertEquals(expected.message, actual.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNip04Decrypt() {
|
||||
val expected = BunkerRequestNip04Decrypt(pubKey = peer.pubKey, ciphertext = "Test")
|
||||
val actual = encodeDecodeEvent(expected)
|
||||
|
||||
assertEquals(expected.method, actual.method)
|
||||
assertEquals(expected.id, actual.id)
|
||||
assertEquals(expected.pubKey, actual.pubKey)
|
||||
assertEquals(expected.ciphertext, actual.ciphertext)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNip44Decrypt() {
|
||||
val expected = BunkerRequestNip44Decrypt(pubKey = peer.pubKey, ciphertext = "Test")
|
||||
val actual = encodeDecodeEvent(expected)
|
||||
|
||||
assertEquals(expected.method, actual.method)
|
||||
assertEquals(expected.id, actual.id)
|
||||
assertEquals(expected.pubKey, actual.pubKey)
|
||||
assertEquals(expected.ciphertext, actual.ciphertext)
|
||||
}
|
||||
|
||||
// Responses
|
||||
|
||||
@Test
|
||||
fun testAckResponse() {
|
||||
val expected = BunkerResponseAck()
|
||||
val actual = encodeDecodeEvent(expected)
|
||||
|
||||
assertEquals(expected.id, actual.id)
|
||||
assertEquals(expected.result, actual.result)
|
||||
assertEquals(expected.error, actual.error)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPongResponse() {
|
||||
val expected = BunkerResponsePong()
|
||||
val actual = encodeDecodeEvent(expected)
|
||||
|
||||
assertEquals(expected.id, actual.id)
|
||||
assertEquals(expected.result, actual.result)
|
||||
assertEquals(expected.error, actual.error)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testErrorResponse() {
|
||||
val expected = BunkerResponseError(error = "Error")
|
||||
val actual = encodeDecodeEvent(expected)
|
||||
|
||||
assertEquals(expected.id, actual.id)
|
||||
assertEquals(expected.result, actual.result)
|
||||
assertEquals(expected.error, actual.error)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEventResponse() {
|
||||
val expected = BunkerResponseEvent(event = dummyEvent)
|
||||
val actual = encodeDecodeEvent(expected)
|
||||
|
||||
assertEquals(expected.id, actual.id)
|
||||
assertEquals(expected.result, actual.result)
|
||||
assertEquals(expected.error, actual.error)
|
||||
assertEquals(dummyEvent.id, actual.event.id)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPubkeyResponse() {
|
||||
val expected = BunkerResponsePublicKey(pubkey = peer.pubKey)
|
||||
val actual = encodeDecodeEvent(expected)
|
||||
|
||||
assertEquals(expected.id, actual.id)
|
||||
assertEquals(expected.result, actual.result)
|
||||
assertEquals(expected.error, actual.error)
|
||||
assertEquals(expected.pubkey, actual.pubkey)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRelaysResponse() {
|
||||
val expected = BunkerResponseGetRelays(relays = mapOf("url" to ContactListEvent.ReadWrite(true, false)))
|
||||
val actual = encodeDecodeEvent(expected)
|
||||
|
||||
assertEquals(expected.id, actual.id)
|
||||
assertEquals(expected.result, actual.result)
|
||||
assertEquals(expected.error, actual.error)
|
||||
assertEquals(expected.relays["url"], actual.relays["url"])
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Impossible to recreate the class since there are no hints on the json")
|
||||
fun testDecryptResponse() {
|
||||
val expected = BunkerResponseDecrypt(plaintext = "Test")
|
||||
val actual = encodeDecodeEvent(expected)
|
||||
|
||||
assertEquals(expected.id, actual.id)
|
||||
assertEquals(expected.result, actual.result)
|
||||
assertEquals(expected.error, actual.error)
|
||||
assertEquals(expected.plaintext, actual.plaintext)
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Impossible to recreate the class since there are no hints on the json")
|
||||
fun testEncryptResponse() {
|
||||
val expected = BunkerResponseEncrypt(ciphertext = "Test")
|
||||
val actual = encodeDecodeEvent(expected)
|
||||
|
||||
assertEquals(expected.id, actual.id)
|
||||
assertEquals(expected.result, actual.result)
|
||||
assertEquals(expected.error, actual.error)
|
||||
assertEquals(expected.ciphertext, actual.ciphertext)
|
||||
}
|
||||
}
|
@ -43,6 +43,9 @@ import com.vitorpamplona.quartz.encoders.Nip01Serializer
|
||||
import com.vitorpamplona.quartz.encoders.Nip19Bech32
|
||||
import com.vitorpamplona.quartz.encoders.PoWRank
|
||||
import com.vitorpamplona.quartz.encoders.toHexKey
|
||||
import com.vitorpamplona.quartz.events.nip46.BunkerMessage
|
||||
import com.vitorpamplona.quartz.events.nip46.BunkerRequest
|
||||
import com.vitorpamplona.quartz.events.nip46.BunkerResponse
|
||||
import com.vitorpamplona.quartz.signers.NostrSigner
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
import com.vitorpamplona.quartz.utils.bytesUsedInMemory
|
||||
@ -435,7 +438,12 @@ open class Event(
|
||||
.addSerializer(Gossip::class.java, GossipSerializer())
|
||||
.addDeserializer(Gossip::class.java, GossipDeserializer())
|
||||
.addDeserializer(Response::class.java, ResponseDeserializer())
|
||||
.addDeserializer(Request::class.java, RequestDeserializer()),
|
||||
.addDeserializer(Request::class.java, RequestDeserializer())
|
||||
.addDeserializer(BunkerMessage::class.java, BunkerMessage.BunkerMessageDeserializer())
|
||||
.addSerializer(BunkerRequest::class.java, BunkerRequest.BunkerRequestSerializer())
|
||||
.addDeserializer(BunkerRequest::class.java, BunkerRequest.BunkerRequestDeserializer())
|
||||
.addSerializer(BunkerResponse::class.java, BunkerResponse.BunkerResponseSerializer())
|
||||
.addDeserializer(BunkerResponse::class.java, BunkerResponse.BunkerResponseDeserializer()),
|
||||
)
|
||||
|
||||
fun fromJson(jsonObject: JsonNode): Event =
|
||||
@ -452,7 +460,7 @@ open class Event(
|
||||
sig = jsonObject.get("sig").asText(),
|
||||
)
|
||||
|
||||
private inline fun <reified R> JsonNode.toTypedArray(transform: (JsonNode) -> R): Array<R> = Array(size()) { transform(get(it)) }
|
||||
inline fun <reified R> JsonNode.toTypedArray(transform: (JsonNode) -> R): Array<R> = Array(size()) { transform(get(it)) }
|
||||
|
||||
fun fromJson(json: String): Event = mapper.readValue(json, Event::class.java)
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
package com.vitorpamplona.quartz.events
|
||||
|
||||
import com.vitorpamplona.quartz.encoders.toHexKey
|
||||
import com.vitorpamplona.quartz.events.nip46.NostrConnectEvent
|
||||
|
||||
class EventFactory {
|
||||
companion object {
|
||||
@ -120,6 +121,7 @@ class EventFactory {
|
||||
MetadataEvent.KIND -> MetadataEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
MuteListEvent.KIND -> MuteListEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
NNSEvent.KIND -> NNSEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
NostrConnectEvent.KIND -> NostrConnectEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
NIP90StatusEvent.KIND -> NIP90StatusEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
NIP90ContentDiscoveryRequestEvent.KIND -> NIP90ContentDiscoveryRequestEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
NIP90ContentDiscoveryResponseEvent.KIND -> NIP90ContentDiscoveryResponseEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
|
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2024 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.events.nip46
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser
|
||||
import com.fasterxml.jackson.databind.DeserializationContext
|
||||
import com.fasterxml.jackson.databind.JsonNode
|
||||
import com.fasterxml.jackson.databind.deser.std.StdDeserializer
|
||||
|
||||
abstract class BunkerMessage {
|
||||
abstract fun countMemory(): Long
|
||||
|
||||
class BunkerMessageDeserializer : StdDeserializer<BunkerMessage>(BunkerMessage::class.java) {
|
||||
override fun deserialize(
|
||||
jp: JsonParser,
|
||||
ctxt: DeserializationContext,
|
||||
): BunkerMessage {
|
||||
val jsonObject: JsonNode = jp.codec.readTree(jp)
|
||||
val isRequest = jsonObject.has("method")
|
||||
|
||||
if (isRequest) {
|
||||
return jp.codec.treeToValue(jsonObject, BunkerRequest::class.java)
|
||||
} else {
|
||||
return jp.codec.treeToValue(jsonObject, BunkerResponse::class.java)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Copyright (c) 2024 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.events.nip46
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator
|
||||
import com.fasterxml.jackson.core.JsonParser
|
||||
import com.fasterxml.jackson.databind.DeserializationContext
|
||||
import com.fasterxml.jackson.databind.JsonNode
|
||||
import com.fasterxml.jackson.databind.SerializerProvider
|
||||
import com.fasterxml.jackson.databind.deser.std.StdDeserializer
|
||||
import com.fasterxml.jackson.databind.ser.std.StdSerializer
|
||||
import com.vitorpamplona.quartz.events.Event.Companion.toTypedArray
|
||||
import com.vitorpamplona.quartz.utils.bytesUsedInMemory
|
||||
import com.vitorpamplona.quartz.utils.pointerSizeInBytes
|
||||
|
||||
open class BunkerRequest(
|
||||
val id: String,
|
||||
val method: String,
|
||||
val params: Array<String> = emptyArray(),
|
||||
) : BunkerMessage() {
|
||||
override fun countMemory(): Long =
|
||||
3 * pointerSizeInBytes + // 3 fields, 4 bytes each reference (32bit)
|
||||
id.bytesUsedInMemory() +
|
||||
method.bytesUsedInMemory() +
|
||||
params.sumOf { pointerSizeInBytes + it.bytesUsedInMemory() }
|
||||
|
||||
class BunkerRequestDeserializer : StdDeserializer<BunkerRequest>(BunkerRequest::class.java) {
|
||||
override fun deserialize(
|
||||
jp: JsonParser,
|
||||
ctxt: DeserializationContext,
|
||||
): BunkerRequest {
|
||||
val jsonObject: JsonNode = jp.codec.readTree(jp)
|
||||
val id = jsonObject.get("id").asText().intern()
|
||||
val method = jsonObject.get("method").asText().intern()
|
||||
val params = jsonObject.get("params")?.toTypedArray { it.asText().intern() } ?: emptyArray()
|
||||
|
||||
return when (method) {
|
||||
BunkerRequestConnect.METHOD_NAME -> BunkerRequestConnect.parse(id, params)
|
||||
BunkerRequestGetPublicKey.METHOD_NAME -> BunkerRequestGetPublicKey.parse(id, params)
|
||||
BunkerRequestGetRelays.METHOD_NAME -> BunkerRequestGetRelays.parse(id, params)
|
||||
|
||||
BunkerRequestNip04Decrypt.METHOD_NAME -> BunkerRequestNip04Decrypt.parse(id, params)
|
||||
BunkerRequestNip04Encrypt.METHOD_NAME -> BunkerRequestNip04Encrypt.parse(id, params)
|
||||
BunkerRequestNip44Decrypt.METHOD_NAME -> BunkerRequestNip44Decrypt.parse(id, params)
|
||||
BunkerRequestNip44Encrypt.METHOD_NAME -> BunkerRequestNip44Encrypt.parse(id, params)
|
||||
|
||||
BunkerRequestPing.METHOD_NAME -> BunkerRequestPing.parse(id, params)
|
||||
BunkerRequestSign.METHOD_NAME -> BunkerRequestSign.parse(id, params)
|
||||
else -> BunkerRequest(id, method, params)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BunkerRequestSerializer : StdSerializer<BunkerRequest>(BunkerRequest::class.java) {
|
||||
override fun serialize(
|
||||
value: BunkerRequest,
|
||||
gen: JsonGenerator,
|
||||
provider: SerializerProvider,
|
||||
) {
|
||||
gen.writeStartObject()
|
||||
gen.writeStringField("id", value.id)
|
||||
gen.writeStringField("method", value.method)
|
||||
gen.writeArrayFieldStart("params")
|
||||
value.params.forEach {
|
||||
gen.writeString(it)
|
||||
}
|
||||
gen.writeEndArray()
|
||||
gen.writeEndObject()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2024 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.events.nip46
|
||||
|
||||
import com.vitorpamplona.quartz.encoders.HexKey
|
||||
import java.util.UUID
|
||||
|
||||
class BunkerRequestConnect(
|
||||
id: String = UUID.randomUUID().toString(),
|
||||
val remoteKey: HexKey,
|
||||
val secret: HexKey? = null,
|
||||
val permissions: String? = null,
|
||||
) : BunkerRequest(id, METHOD_NAME, listOfNotNull(remoteKey, secret, permissions).toTypedArray()) {
|
||||
companion object {
|
||||
val METHOD_NAME = "connect"
|
||||
|
||||
fun parse(
|
||||
id: String,
|
||||
params: Array<String>,
|
||||
): BunkerRequestConnect = BunkerRequestConnect(id, params[0], params.getOrNull(1), params.getOrNull(2))
|
||||
}
|
||||
}
|
||||
|
||||
public fun <T> Array<T>.getOrNull(index: Int): T? = if (index in 0..<size) get(index) else null
|
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2024 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.events.nip46
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
class BunkerRequestGetPublicKey(
|
||||
id: String = UUID.randomUUID().toString(),
|
||||
) : BunkerRequest(id, METHOD_NAME, arrayOf()) {
|
||||
companion object {
|
||||
val METHOD_NAME = "get_public_key"
|
||||
|
||||
fun parse(
|
||||
id: String,
|
||||
params: Array<String>,
|
||||
): BunkerRequestGetPublicKey = BunkerRequestGetPublicKey(id)
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2024 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.events.nip46
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
class BunkerRequestGetRelays(
|
||||
id: String = UUID.randomUUID().toString(),
|
||||
) : BunkerRequest(id, METHOD_NAME, arrayOf()) {
|
||||
companion object {
|
||||
val METHOD_NAME = "get_relays"
|
||||
|
||||
fun parse(
|
||||
id: String,
|
||||
params: Array<String>,
|
||||
): BunkerRequestGetRelays = BunkerRequestGetRelays(id)
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2024 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.events.nip46
|
||||
|
||||
import com.vitorpamplona.quartz.encoders.HexKey
|
||||
import java.util.UUID
|
||||
|
||||
class BunkerRequestNip04Decrypt(
|
||||
id: String = UUID.randomUUID().toString(),
|
||||
val pubKey: HexKey,
|
||||
val ciphertext: String,
|
||||
) : BunkerRequest(id, METHOD_NAME, listOfNotNull(pubKey, ciphertext).toTypedArray()) {
|
||||
companion object {
|
||||
val METHOD_NAME = "nip04_decrypt"
|
||||
|
||||
fun parse(
|
||||
id: String,
|
||||
params: Array<String>,
|
||||
): BunkerRequestNip04Decrypt = BunkerRequestNip04Decrypt(id, params[0], params.get(1))
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2024 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.events.nip46
|
||||
|
||||
import com.vitorpamplona.quartz.encoders.HexKey
|
||||
import java.util.UUID
|
||||
|
||||
class BunkerRequestNip04Encrypt(
|
||||
id: String = UUID.randomUUID().toString(),
|
||||
val pubKey: HexKey,
|
||||
val message: String,
|
||||
) : BunkerRequest(id, METHOD_NAME, listOfNotNull(pubKey, message).toTypedArray()) {
|
||||
companion object {
|
||||
val METHOD_NAME = "nip04_encrypt"
|
||||
|
||||
fun parse(
|
||||
id: String,
|
||||
params: Array<String>,
|
||||
): BunkerRequestNip04Encrypt = BunkerRequestNip04Encrypt(id, params[0], params.get(1))
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2024 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.events.nip46
|
||||
|
||||
import com.vitorpamplona.quartz.encoders.HexKey
|
||||
import java.util.UUID
|
||||
|
||||
class BunkerRequestNip44Decrypt(
|
||||
id: String = UUID.randomUUID().toString(),
|
||||
val pubKey: HexKey,
|
||||
val ciphertext: String,
|
||||
) : BunkerRequest(id, METHOD_NAME, listOfNotNull(pubKey, ciphertext).toTypedArray()) {
|
||||
companion object {
|
||||
val METHOD_NAME = "nip44_decrypt"
|
||||
|
||||
fun parse(
|
||||
id: String,
|
||||
params: Array<String>,
|
||||
): BunkerRequestNip44Decrypt = BunkerRequestNip44Decrypt(id, params[0], params.get(1))
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2024 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.events.nip46
|
||||
|
||||
import com.vitorpamplona.quartz.encoders.HexKey
|
||||
import java.util.UUID
|
||||
|
||||
class BunkerRequestNip44Encrypt(
|
||||
id: String = UUID.randomUUID().toString(),
|
||||
val pubKey: HexKey,
|
||||
val message: String,
|
||||
) : BunkerRequest(id, METHOD_NAME, listOfNotNull(pubKey, message).toTypedArray()) {
|
||||
companion object {
|
||||
val METHOD_NAME = "nip44_encrypt"
|
||||
|
||||
fun parse(
|
||||
id: String,
|
||||
params: Array<String>,
|
||||
): BunkerRequestNip44Encrypt = BunkerRequestNip44Encrypt(id, params[0], params.get(1))
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2024 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.events.nip46
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
class BunkerRequestPing(
|
||||
id: String = UUID.randomUUID().toString(),
|
||||
) : BunkerRequest(id, METHOD_NAME, arrayOf()) {
|
||||
companion object {
|
||||
val METHOD_NAME = "ping"
|
||||
|
||||
fun parse(
|
||||
id: String,
|
||||
params: Array<String>,
|
||||
): BunkerRequestPing = BunkerRequestPing(id)
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) 2024 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.events.nip46
|
||||
|
||||
import com.vitorpamplona.quartz.events.Event
|
||||
import java.util.UUID
|
||||
|
||||
class BunkerRequestSign(
|
||||
id: String = UUID.randomUUID().toString(),
|
||||
val event: Event,
|
||||
) : BunkerRequest(id, METHOD_NAME, arrayOf(event.toJson())) {
|
||||
companion object {
|
||||
val METHOD_NAME = "sign_event"
|
||||
|
||||
fun parse(
|
||||
id: String,
|
||||
params: Array<String>,
|
||||
): BunkerRequestSign = BunkerRequestSign(id, Event.fromJson(params[0]))
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
/**
|
||||
* Copyright (c) 2024 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.events.nip46
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator
|
||||
import com.fasterxml.jackson.core.JsonParser
|
||||
import com.fasterxml.jackson.databind.DeserializationContext
|
||||
import com.fasterxml.jackson.databind.JsonNode
|
||||
import com.fasterxml.jackson.databind.SerializerProvider
|
||||
import com.fasterxml.jackson.databind.deser.std.StdDeserializer
|
||||
import com.fasterxml.jackson.databind.ser.std.StdSerializer
|
||||
import com.vitorpamplona.quartz.encoders.HexValidator
|
||||
import com.vitorpamplona.quartz.utils.bytesUsedInMemory
|
||||
import com.vitorpamplona.quartz.utils.pointerSizeInBytes
|
||||
|
||||
open class BunkerResponse(
|
||||
val id: String,
|
||||
val result: String?,
|
||||
val error: String?,
|
||||
) : BunkerMessage() {
|
||||
override fun countMemory(): Long =
|
||||
3 * pointerSizeInBytes + // 3 fields, 4 bytes each reference (32bit)
|
||||
id.bytesUsedInMemory() +
|
||||
(result?.bytesUsedInMemory() ?: 0) +
|
||||
(error?.bytesUsedInMemory() ?: 0)
|
||||
|
||||
class BunkerResponseDeserializer : StdDeserializer<BunkerResponse>(BunkerResponse::class.java) {
|
||||
override fun deserialize(
|
||||
jp: JsonParser,
|
||||
ctxt: DeserializationContext,
|
||||
): BunkerResponse {
|
||||
val jsonObject: JsonNode = jp.codec.readTree(jp)
|
||||
|
||||
val id = jsonObject.get("id").asText().intern()
|
||||
val result = jsonObject.get("result")?.asText()
|
||||
val error = jsonObject.get("error")?.asText()
|
||||
|
||||
if (error != null) {
|
||||
return BunkerResponseError.parse(id, result, error)
|
||||
}
|
||||
|
||||
if (result != null) {
|
||||
when (result) {
|
||||
BunkerResponseAck.RESULT -> return BunkerResponseAck.parse(id, result, error)
|
||||
BunkerResponsePong.RESULT -> return BunkerResponsePong.parse(id, result, error)
|
||||
else -> {
|
||||
if (result.length == 64 && HexValidator.isHex(result)) {
|
||||
return BunkerResponsePublicKey.parse(id, result)
|
||||
}
|
||||
|
||||
if (result.get(0) == '{') {
|
||||
try {
|
||||
return BunkerResponseEvent.parse(id, result)
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
|
||||
try {
|
||||
return BunkerResponseGetRelays.parse(id, result)
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
}
|
||||
|
||||
return BunkerResponse(id, result, error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return BunkerResponse(id, result, error)
|
||||
}
|
||||
}
|
||||
|
||||
class BunkerResponseSerializer : StdSerializer<BunkerResponse>(BunkerResponse::class.java) {
|
||||
override fun serialize(
|
||||
value: BunkerResponse,
|
||||
gen: JsonGenerator,
|
||||
provider: SerializerProvider,
|
||||
) {
|
||||
gen.writeStartObject()
|
||||
gen.writeStringField("id", value.id)
|
||||
value.result?.let { gen.writeStringField("result", value.result) }
|
||||
value.error?.let { gen.writeStringField("error", it) }
|
||||
gen.writeEndObject()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2024 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.events.nip46
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
class BunkerResponseAck(
|
||||
id: String = UUID.randomUUID().toString(),
|
||||
) : BunkerResponse(id, RESULT, null) {
|
||||
companion object {
|
||||
val RESULT = "ack"
|
||||
|
||||
fun parse(
|
||||
id: String,
|
||||
result: String,
|
||||
error: String? = null,
|
||||
) = BunkerResponseAck(id)
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2024 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.events.nip46
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
class BunkerResponseDecrypt(
|
||||
id: String = UUID.randomUUID().toString(),
|
||||
val plaintext: String,
|
||||
) : BunkerResponse(id, plaintext, null) {
|
||||
companion object {
|
||||
fun parse(
|
||||
id: String,
|
||||
result: String,
|
||||
error: String? = null,
|
||||
) = BunkerResponseDecrypt(id, result)
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2024 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.events.nip46
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
class BunkerResponseEncrypt(
|
||||
id: String = UUID.randomUUID().toString(),
|
||||
val ciphertext: String,
|
||||
) : BunkerResponse(id, ciphertext, null) {
|
||||
companion object {
|
||||
fun parse(
|
||||
id: String,
|
||||
result: String,
|
||||
error: String? = null,
|
||||
) = BunkerResponseEncrypt(id, result)
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2024 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.events.nip46
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
class BunkerResponseError(
|
||||
id: String = UUID.randomUUID().toString(),
|
||||
error: String,
|
||||
) : BunkerResponse(id, null, error) {
|
||||
companion object {
|
||||
fun parse(
|
||||
id: String,
|
||||
result: String? = null,
|
||||
error: String,
|
||||
) = BunkerResponseError(id, error)
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2024 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.events.nip46
|
||||
|
||||
import com.vitorpamplona.quartz.events.Event
|
||||
import java.util.UUID
|
||||
|
||||
class BunkerResponseEvent(
|
||||
id: String = UUID.randomUUID().toString(),
|
||||
val event: Event,
|
||||
) : BunkerResponse(id, event.toJson(), null) {
|
||||
companion object {
|
||||
fun parse(
|
||||
id: String,
|
||||
result: String,
|
||||
error: String? = null,
|
||||
) = BunkerResponseEvent(id, Event.fromJson(result))
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2024 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.events.nip46
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference
|
||||
import com.vitorpamplona.quartz.events.ContactListEvent.ReadWrite
|
||||
import com.vitorpamplona.quartz.events.Event
|
||||
import java.util.UUID
|
||||
|
||||
class BunkerResponseGetRelays(
|
||||
id: String = UUID.randomUUID().toString(),
|
||||
val relays: Map<String, ReadWrite>,
|
||||
) : BunkerResponse(id, Event.mapper.writeValueAsString(relays), null) {
|
||||
companion object {
|
||||
fun parse(
|
||||
id: String,
|
||||
result: String,
|
||||
error: String? = null,
|
||||
) = BunkerResponseGetRelays(id, Event.mapper.readValue(result, object : TypeReference<Map<String, ReadWrite>>() {}))
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2024 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.events.nip46
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
class BunkerResponsePong(
|
||||
id: String = UUID.randomUUID().toString(),
|
||||
) : BunkerResponse(id, RESULT, null) {
|
||||
companion object {
|
||||
val RESULT = "pong"
|
||||
|
||||
fun parse(
|
||||
id: String,
|
||||
result: String,
|
||||
error: String? = null,
|
||||
) = BunkerResponsePong(id)
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2024 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.events.nip46
|
||||
|
||||
import com.vitorpamplona.quartz.encoders.HexKey
|
||||
import java.util.UUID
|
||||
|
||||
class BunkerResponsePublicKey(
|
||||
id: String = UUID.randomUUID().toString(),
|
||||
val pubkey: HexKey,
|
||||
) : BunkerResponse(id, pubkey, null) {
|
||||
companion object {
|
||||
fun parse(
|
||||
id: String,
|
||||
result: String,
|
||||
error: String? = null,
|
||||
) = BunkerResponsePublicKey(id, result)
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
/**
|
||||
* Copyright (c) 2024 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.events.nip46
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.vitorpamplona.quartz.encoders.Hex
|
||||
import com.vitorpamplona.quartz.encoders.HexKey
|
||||
import com.vitorpamplona.quartz.encoders.HexValidator
|
||||
import com.vitorpamplona.quartz.events.Event
|
||||
import com.vitorpamplona.quartz.signers.NostrSigner
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
import com.vitorpamplona.quartz.utils.pointerSizeInBytes
|
||||
|
||||
@Immutable
|
||||
class NostrConnectEvent(
|
||||
id: HexKey,
|
||||
pubKey: HexKey,
|
||||
createdAt: Long,
|
||||
tags: Array<Array<String>>,
|
||||
content: String,
|
||||
sig: HexKey,
|
||||
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||
@Transient private var decryptedContent: Map<HexKey, BunkerMessage> = mapOf()
|
||||
|
||||
override fun countMemory(): Long =
|
||||
super.countMemory() +
|
||||
pointerSizeInBytes + (decryptedContent.values.sumOf { pointerSizeInBytes + it.countMemory() })
|
||||
|
||||
override fun isContentEncoded() = true
|
||||
|
||||
private fun recipientPubKey() = tags.firstOrNull { it.size > 1 && it[0] == "p" }?.get(1)
|
||||
|
||||
fun recipientPubKeyBytes() = recipientPubKey()?.runCatching { Hex.decode(this) }?.getOrNull()
|
||||
|
||||
fun verifiedRecipientPubKey(): HexKey? {
|
||||
val recipient = recipientPubKey()
|
||||
return if (HexValidator.isHex(recipient)) {
|
||||
recipient
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun talkingWith(oneSideHex: String): HexKey = if (pubKey == oneSideHex) verifiedRecipientPubKey() ?: pubKey else pubKey
|
||||
|
||||
fun plainContent(
|
||||
signer: NostrSigner,
|
||||
onReady: (BunkerMessage) -> Unit,
|
||||
) {
|
||||
decryptedContent[signer.pubKey]?.let {
|
||||
onReady(it)
|
||||
return
|
||||
}
|
||||
|
||||
// decrypts using NIP-04 or NIP-44
|
||||
signer.decrypt(content, talkingWith(signer.pubKey)) { retVal ->
|
||||
val content = Event.mapper.readValue(retVal, BunkerMessage::class.java)
|
||||
|
||||
decryptedContent = decryptedContent + Pair(signer.pubKey, content)
|
||||
|
||||
onReady(content)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val KIND = 24133
|
||||
const val ALT = "Nostr Connect Event"
|
||||
|
||||
fun create(
|
||||
message: BunkerMessage,
|
||||
remoteKey: HexKey,
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
onReady: (NostrConnectEvent) -> Unit,
|
||||
) {
|
||||
val tags =
|
||||
arrayOf(
|
||||
arrayOf("alt", ALT),
|
||||
arrayOf("p", remoteKey),
|
||||
)
|
||||
signer.sign(createdAt, KIND, tags, "", onReady)
|
||||
|
||||
val encrypted = mapper.writeValueAsString(message)
|
||||
|
||||
signer.nip44Encrypt(encrypted, remoteKey) { content ->
|
||||
signer.sign(createdAt, KIND, tags, content, onReady)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user