mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2024-09-29 16:30:49 +00:00
commit
a84be7fc61
@ -1,71 +1,103 @@
|
|||||||
package com.vitorpamplona.amethyst.service
|
package com.vitorpamplona.amethyst.service
|
||||||
|
|
||||||
import com.vitorpamplona.amethyst.model.toByteArray
|
|
||||||
import com.vitorpamplona.amethyst.model.toHexKey
|
import com.vitorpamplona.amethyst.model.toHexKey
|
||||||
import com.vitorpamplona.amethyst.service.model.ATag
|
import nostr.postr.bechToBytes
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
import java.nio.ByteOrder
|
import java.nio.ByteOrder
|
||||||
import nostr.postr.Bech32
|
|
||||||
import nostr.postr.bechToBytes
|
|
||||||
import nostr.postr.toByteArray
|
|
||||||
|
|
||||||
class Nip19 {
|
class Nip19 {
|
||||||
|
|
||||||
enum class Type {
|
enum class Type {
|
||||||
USER, NOTE, RELAY, ADDRESS
|
USER, NOTE, RELAY, ADDRESS
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Return(val type: Type, val hex: String)
|
data class Return(val type: Type, val hex: String)
|
||||||
|
|
||||||
fun uriToRoute(uri: String?): Return? {
|
fun uriToRoute(uri: String?): Return? {
|
||||||
try {
|
try {
|
||||||
val key = uri?.removePrefix("nostr:")
|
val key = uri?.removePrefix("nostr:") ?: return null
|
||||||
|
|
||||||
if (key != null) {
|
val bytes = key.bechToBytes()
|
||||||
val bytes = key.bechToBytes()
|
if (key.startsWith("npub")) {
|
||||||
if (key.startsWith("npub")) {
|
return npub(bytes)
|
||||||
return Return(Type.USER, bytes.toHexKey())
|
} else if (key.startsWith("note")) {
|
||||||
}
|
return note(bytes)
|
||||||
if (key.startsWith("note")) {
|
} else if (key.startsWith("nprofile")) {
|
||||||
return Return(Type.NOTE, bytes.toHexKey())
|
return nprofile(bytes)
|
||||||
}
|
} else if (key.startsWith("nevent")) {
|
||||||
if (key.startsWith("nprofile")) {
|
return nevent(bytes)
|
||||||
val tlv = parseTLV(bytes)
|
} else if (key.startsWith("nrelay")) {
|
||||||
val hex = tlv.get(NIP19TLVTypes.SPECIAL.id)?.get(0)?.toHexKey()
|
return nrelay(bytes)
|
||||||
if (hex != null)
|
} else if (key.startsWith("naddr")) {
|
||||||
return Return(Type.USER, hex)
|
return naddr(bytes)
|
||||||
}
|
|
||||||
if (key.startsWith("nevent")) {
|
|
||||||
val tlv = parseTLV(bytes)
|
|
||||||
val hex = tlv.get(NIP19TLVTypes.SPECIAL.id)?.get(0)?.toHexKey()
|
|
||||||
if (hex != null)
|
|
||||||
return Return(Type.USER, hex)
|
|
||||||
}
|
|
||||||
if (key.startsWith("nrelay")) {
|
|
||||||
val tlv = parseTLV(bytes)
|
|
||||||
val relayUrl = tlv.get(NIP19TLVTypes.SPECIAL.id)?.get(0)?.toString(Charsets.UTF_8)
|
|
||||||
if (relayUrl != null)
|
|
||||||
return Return(Type.RELAY, relayUrl)
|
|
||||||
}
|
|
||||||
if (key.startsWith("naddr")) {
|
|
||||||
val tlv = parseTLV(bytes)
|
|
||||||
val d = tlv.get(NIP19TLVTypes.SPECIAL.id)?.get(0)?.toString(Charsets.UTF_8)
|
|
||||||
val relay = tlv.get(NIP19TLVTypes.RELAY.id)?.get(0)?.toString(Charsets.UTF_8)
|
|
||||||
val author = tlv.get(NIP19TLVTypes.AUTHOR.id)?.get(0)?.toHexKey()
|
|
||||||
val kind = tlv.get(NIP19TLVTypes.KIND.id)?.get(0)?.let { toInt32(it) }
|
|
||||||
if (d != null)
|
|
||||||
return Return(Type.ADDRESS, "$kind:$author:$d")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
println("Issue trying to Decode NIP19 ${uri}: ${e.message}")
|
println("Issue trying to Decode NIP19 ${uri}: ${e.message}")
|
||||||
//e.printStackTrace()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun npub(bytes: ByteArray): Return {
|
||||||
|
return Return(Type.USER, bytes.toHexKey())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun note(bytes: ByteArray): Return {
|
||||||
|
return Return(Type.NOTE, bytes.toHexKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun nprofile(bytes: ByteArray): Return? {
|
||||||
|
val hex = parseTLV(bytes)
|
||||||
|
.get(NIP19TLVTypes.SPECIAL.id)
|
||||||
|
?.get(0)
|
||||||
|
?.toHexKey() ?: return null
|
||||||
|
|
||||||
|
return Return(Type.USER, hex)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun nevent(bytes: ByteArray): Return? {
|
||||||
|
val hex = parseTLV(bytes)
|
||||||
|
.get(NIP19TLVTypes.SPECIAL.id)
|
||||||
|
?.get(0)
|
||||||
|
?.toHexKey() ?: return null
|
||||||
|
|
||||||
|
return Return(Type.USER, hex)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun nrelay(bytes: ByteArray): Return? {
|
||||||
|
val relayUrl = parseTLV(bytes)
|
||||||
|
.get(NIP19TLVTypes.SPECIAL.id)
|
||||||
|
?.get(0)
|
||||||
|
?.toString(Charsets.UTF_8) ?: return null
|
||||||
|
|
||||||
|
return Return(Type.RELAY, relayUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun naddr(bytes: ByteArray): Return? {
|
||||||
|
val tlv = parseTLV(bytes)
|
||||||
|
|
||||||
|
val d = tlv.get(NIP19TLVTypes.SPECIAL.id)
|
||||||
|
?.get(0)
|
||||||
|
?.toString(Charsets.UTF_8) ?: return null
|
||||||
|
|
||||||
|
val relay = tlv.get(NIP19TLVTypes.RELAY.id)
|
||||||
|
?.get(0)
|
||||||
|
?.toString(Charsets.UTF_8)
|
||||||
|
|
||||||
|
val author = tlv.get(NIP19TLVTypes.AUTHOR.id)
|
||||||
|
?.get(0)
|
||||||
|
?.toHexKey()
|
||||||
|
|
||||||
|
val kind = tlv.get(NIP19TLVTypes.KIND.id)
|
||||||
|
?.get(0)
|
||||||
|
?.let { toInt32(it) }
|
||||||
|
|
||||||
|
return Return(Type.ADDRESS, "$kind:$author:$d")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class NIP19TLVTypes(val id: Byte) { //classes should start with an uppercase letter in kotlin
|
// Classes should start with an uppercase letter in kotlin
|
||||||
|
enum class NIP19TLVTypes(val id: Byte) {
|
||||||
SPECIAL(0),
|
SPECIAL(0),
|
||||||
RELAY(1),
|
RELAY(1),
|
||||||
AUTHOR(2),
|
AUTHOR(2),
|
||||||
@ -78,19 +110,19 @@ fun toInt32(bytes: ByteArray): Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun parseTLV(data: ByteArray): Map<Byte, List<ByteArray>> {
|
fun parseTLV(data: ByteArray): Map<Byte, List<ByteArray>> {
|
||||||
var result = mutableMapOf<Byte, MutableList<ByteArray>>()
|
val result = mutableMapOf<Byte, MutableList<ByteArray>>()
|
||||||
var rest = data
|
var rest = data
|
||||||
while (rest.isNotEmpty()) {
|
while (rest.isNotEmpty()) {
|
||||||
val t = rest[0]
|
val t = rest[0]
|
||||||
val l = rest[1]
|
val l = rest[1]
|
||||||
val v = rest.sliceArray(IntRange(2, (2 + l) - 1))
|
val v = rest.sliceArray(IntRange(2, (2 + l) - 1))
|
||||||
rest = rest.sliceArray(IntRange(2 + l, rest.size-1))
|
rest = rest.sliceArray(IntRange(2 + l, rest.size - 1))
|
||||||
if (v.size < l) continue
|
if (v.size < l) continue
|
||||||
|
|
||||||
if (!result.containsKey(t)) {
|
if (!result.containsKey(t)) {
|
||||||
result.put(t, mutableListOf())
|
result[t] = mutableListOf()
|
||||||
}
|
}
|
||||||
result.get(t)?.add(v)
|
result[t]?.add(v)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,109 @@
|
|||||||
|
package com.vitorpamplona.amethyst.service
|
||||||
|
|
||||||
|
import org.junit.Assert
|
||||||
|
import org.junit.Ignore
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class Nip19Test {
|
||||||
|
|
||||||
|
private val nip19 = Nip19();
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException::class)
|
||||||
|
fun to_int_32_length_smaller_than_4() {
|
||||||
|
toInt32(byteArrayOfInts(1, 2, 3))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException::class)
|
||||||
|
fun to_int_32_length_bigger_than_4() {
|
||||||
|
toInt32(byteArrayOfInts(1, 2, 3, 4, 5))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test()
|
||||||
|
fun to_int_32_length_4() {
|
||||||
|
val actual = toInt32(byteArrayOfInts(1, 2, 3, 4))
|
||||||
|
|
||||||
|
Assert.assertEquals(16909060, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Test not implemented yet")
|
||||||
|
@Test()
|
||||||
|
fun parse_TLV() {
|
||||||
|
// TODO: I don't know how to test this (?)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test()
|
||||||
|
fun uri_to_route_null() {
|
||||||
|
val actual = nip19.uriToRoute(null)
|
||||||
|
|
||||||
|
Assert.assertEquals(null, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test()
|
||||||
|
fun uri_to_route_unknown() {
|
||||||
|
val actual = nip19.uriToRoute("nostr:unknown")
|
||||||
|
|
||||||
|
Assert.assertEquals(null, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test()
|
||||||
|
fun uri_to_route_npub() {
|
||||||
|
val actual =
|
||||||
|
nip19.uriToRoute("nostr:npub1hv7k2s755n697sptva8vkh9jz40lzfzklnwj6ekewfmxp5crwdjs27007y")
|
||||||
|
|
||||||
|
Assert.assertEquals(Nip19.Type.USER, actual?.type)
|
||||||
|
Assert.assertEquals(
|
||||||
|
"bb3d6543d4a4f45f402b674ecb5cb2155ff12456fcdd2d66d9727660d3037365",
|
||||||
|
actual?.hex
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test()
|
||||||
|
fun uri_to_route_note() {
|
||||||
|
val actual =
|
||||||
|
nip19.uriToRoute("nostr:note1stqea6wmwezg9x6yyr6qkukw95ewtdukyaztycws65l8wppjmtpscawevv")
|
||||||
|
|
||||||
|
Assert.assertEquals(Nip19.Type.NOTE, actual?.type)
|
||||||
|
Assert.assertEquals(
|
||||||
|
"82c19ee9db7644829b4420f40b72ce2d32e5b7962744b261d0d53e770432dac3",
|
||||||
|
actual?.hex
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Test not implemented yet")
|
||||||
|
@Test()
|
||||||
|
fun uri_to_route_nprofile() {
|
||||||
|
val actual = nip19.uriToRoute("nostr:nprofile")
|
||||||
|
|
||||||
|
Assert.assertEquals(Nip19.Type.USER, actual?.type)
|
||||||
|
Assert.assertEquals("*", actual?.hex)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Test not implemented yet")
|
||||||
|
@Test()
|
||||||
|
fun uri_to_route_nevent() {
|
||||||
|
val actual = nip19.uriToRoute("nostr:nevent")
|
||||||
|
|
||||||
|
Assert.assertEquals(Nip19.Type.USER, actual?.type)
|
||||||
|
Assert.assertEquals("*", actual?.hex)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Test not implemented yet")
|
||||||
|
@Test()
|
||||||
|
fun uri_to_route_nrelay() {
|
||||||
|
val actual = nip19.uriToRoute("nostr:nrelay")
|
||||||
|
|
||||||
|
Assert.assertEquals(Nip19.Type.RELAY, actual?.type)
|
||||||
|
Assert.assertEquals("*", actual?.hex)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("Test not implemented yet")
|
||||||
|
@Test()
|
||||||
|
fun uri_to_route_naddr() {
|
||||||
|
val actual = nip19.uriToRoute("nostr:naddr")
|
||||||
|
|
||||||
|
Assert.assertEquals(Nip19.Type.ADDRESS, actual?.type)
|
||||||
|
Assert.assertEquals("*", actual?.hex)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun byteArrayOfInts(vararg ints: Int) = ByteArray(ints.size) { pos -> ints[pos].toByte() }
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user