mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-09-28 10:56:52 +02:00
Improves RelayHint normalization to make sure the NormalizedRelayUrls are indeed relays
This commit is contained in:
@@ -20,8 +20,12 @@
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip01Core.relay.normalizer
|
||||
|
||||
import android.util.Log
|
||||
import android.util.Log.e
|
||||
import androidx.collection.LruCache
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import org.czeal.rfc3986.URIReference
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
|
||||
val normalizedUrls = LruCache<String, NormalizedRelayUrl>(5000)
|
||||
|
||||
@@ -37,6 +41,27 @@ class RelayUrlNormalizer {
|
||||
|
||||
fun isOnion(url: String) = url.endsWith(".onion") || url.contains(".onion/")
|
||||
|
||||
fun isRelaySchemePrefix(url: String) = url.length > 6 && url[0] == 'w' && url[1] == 's'
|
||||
|
||||
fun isRelaySchemePrefixSecure(url: String) = url[2] == 's' && url[3] == ':' && url[4] == '/' && url[5] == '/' && url[6] != '/'
|
||||
|
||||
fun isRelaySchemePrefixInsecure(url: String) = url[2] == ':' && url[3] == '/' && url[4] == '/' && url[5] != '/'
|
||||
|
||||
fun isRelayUrl(url: String): Boolean {
|
||||
val trimmed = url.trim().ifEmpty { return false }
|
||||
|
||||
// fast
|
||||
if (isRelaySchemePrefix(trimmed)) {
|
||||
if (isRelaySchemePrefixSecure(trimmed)) {
|
||||
return true
|
||||
} else if (isRelaySchemePrefixInsecure(trimmed)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun norm(url: String) =
|
||||
NormalizedRelayUrl(
|
||||
URIReference
|
||||
@@ -46,19 +71,20 @@ class RelayUrlNormalizer {
|
||||
.intern(),
|
||||
)
|
||||
|
||||
fun fix(url: String): String {
|
||||
val trimmed = url.trim()
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
fun fix(url: String): String? {
|
||||
val trimmed = url.trim().ifEmpty { return null }
|
||||
|
||||
// fast
|
||||
if (trimmed.length > 4 && trimmed[0] == 'w' && trimmed[1] == 's') {
|
||||
if (trimmed[2] == 's' && trimmed[3] == ':' && trimmed[4] == '/' && trimmed[5] == '/') {
|
||||
return trimmed
|
||||
} else if (trimmed[2] == ':' && trimmed[3] == '/' && trimmed[4] == '/') {
|
||||
if (trimmed.isEmpty()) return null
|
||||
|
||||
// fast for good wss:// urls
|
||||
if (isRelaySchemePrefix(trimmed)) {
|
||||
if (isRelaySchemePrefixSecure(trimmed) || isRelaySchemePrefixInsecure(trimmed)) {
|
||||
return trimmed
|
||||
}
|
||||
}
|
||||
|
||||
// fast
|
||||
// fast for good https:// urls
|
||||
if (trimmed.length > 8 && trimmed[0] == 'h' && trimmed[1] == 't' && trimmed[2] == 't' && trimmed[3] == 'p') {
|
||||
if (trimmed[4] == 's' && trimmed[5] == ':' && trimmed[6] == '/' && trimmed[7] == '/') {
|
||||
// https://
|
||||
@@ -69,6 +95,12 @@ class RelayUrlNormalizer {
|
||||
}
|
||||
}
|
||||
|
||||
if (trimmed.contains("://")) {
|
||||
// some other scheme we cannot connect to.
|
||||
Log.w("RelayUrlNormalizer", "Rejected relay URL: $url")
|
||||
return null
|
||||
}
|
||||
|
||||
return if (isOnion(trimmed) || isLocalHost(trimmed)) {
|
||||
"ws://$trimmed"
|
||||
} else {
|
||||
@@ -80,7 +112,8 @@ class RelayUrlNormalizer {
|
||||
normalizedUrls.get(url)?.let { return it }
|
||||
|
||||
return try {
|
||||
val normalized = norm(fix(url))
|
||||
val fixed = fix(url) ?: return NormalizedRelayUrl(url)
|
||||
val normalized = norm(fixed)
|
||||
normalizedUrls.put(url, normalized)
|
||||
normalized
|
||||
} catch (e: Exception) {
|
||||
@@ -89,13 +122,22 @@ class RelayUrlNormalizer {
|
||||
}
|
||||
|
||||
fun normalizeOrNull(url: String): NormalizedRelayUrl? {
|
||||
normalizedUrls.get(url)?.let { return it }
|
||||
if (url.isEmpty()) return null
|
||||
normalizedUrls[url]?.let { return it }
|
||||
|
||||
return try {
|
||||
val normalized = norm(fix(url))
|
||||
normalizedUrls.put(url, normalized)
|
||||
normalized
|
||||
val fixed = fix(url)
|
||||
if (fixed != null) {
|
||||
val normalized = norm(fixed)
|
||||
normalizedUrls.put(url, normalized)
|
||||
return normalized
|
||||
} else {
|
||||
Log.w("NormalizedRelayUrl", "Rejected Error $url")
|
||||
null
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
if (e is CancellationException) throw e
|
||||
Log.w("NormalizedRelayUrl", "Rejected Error $url")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip01Core.tags.events
|
||||
|
||||
import android.R.attr.tag
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||
@@ -72,8 +73,7 @@ data class ETag(
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(tag[1].length == 64) { return null }
|
||||
|
||||
val hint = tag.getOrNull(2)?.let { RelayUrlNormalizer.normalizeOrNull(it) }
|
||||
return ETag(tag[1], hint, tag.getOrNull(3))
|
||||
return ETag(tag[1], pickRelayHint(tag), pickAuthor(tag))
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@@ -84,6 +84,32 @@ data class ETag(
|
||||
return tag[1]
|
||||
}
|
||||
|
||||
// simple case ["e", "id", "relay"]
|
||||
// empty tags ["e", "id", "relay", ""]
|
||||
// current root ["e", "id", "relay", "marker"]
|
||||
// current root ["e", "id", "relay", "marker", "pubkey"]
|
||||
// empty tags ["e", "id", "relay", "", "pubkey"]
|
||||
// pubkey marker ["e", "id", "relay", "pubkey"]
|
||||
// pubkey marker ["e", "id", "relay", "pubkey", "marker"]
|
||||
// pubkey marker ["e", "id", "pubkey"] // incorrect
|
||||
// current root ["e", "id", "marker"] // incorrect
|
||||
|
||||
@JvmStatic
|
||||
private fun pickRelayHint(tag: Array<String>): NormalizedRelayUrl? {
|
||||
if (tag.has(2) && tag[2].length > 7 && RelayUrlNormalizer.isRelayUrl(tag[2])) return RelayUrlNormalizer.normalizeOrNull(tag[2])
|
||||
if (tag.has(3) && tag[3].length > 7 && RelayUrlNormalizer.isRelayUrl(tag[3])) return RelayUrlNormalizer.normalizeOrNull(tag[3])
|
||||
if (tag.has(4) && tag[4].length > 7 && RelayUrlNormalizer.isRelayUrl(tag[4])) return RelayUrlNormalizer.normalizeOrNull(tag[4])
|
||||
return null
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
private fun pickAuthor(tag: Array<String>): HexKey? {
|
||||
if (tag.has(2) && tag[2].length == 64) return tag[2]
|
||||
if (tag.has(3) && tag[3].length == 64) return tag[3]
|
||||
if (tag.has(4) && tag[4].length == 64) return tag[4]
|
||||
return null
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun parseAsHint(tag: Array<String>): EventIdHint? {
|
||||
ensure(tag.has(2)) { return null }
|
||||
@@ -91,7 +117,8 @@ data class ETag(
|
||||
ensure(tag[1].length == 64) { return null }
|
||||
ensure(tag[2].isNotEmpty()) { return null }
|
||||
|
||||
val hint = RelayUrlNormalizer.normalizeOrNull(tag[2])
|
||||
val hint = pickRelayHint(tag)
|
||||
|
||||
ensure(hint != null) { return null }
|
||||
|
||||
return EventIdHint(tag[1], hint)
|
||||
|
@@ -66,11 +66,16 @@ data class PTag(
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(tag[1].length == 64) { return null }
|
||||
|
||||
val hint = tag.getOrNull(2)?.let { RelayUrlNormalizer.normalizeOrNull(it) }
|
||||
val hint = pickRelayHint(tag)
|
||||
|
||||
return PTag(tag[1], hint)
|
||||
}
|
||||
|
||||
private fun pickRelayHint(tag: Array<String>): NormalizedRelayUrl? {
|
||||
if (tag.has(2) && tag[2].length > 7 && RelayUrlNormalizer.isRelayUrl(tag[2])) return RelayUrlNormalizer.normalizeOrNull(tag[2])
|
||||
return null
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun parseKey(tag: Array<String>): HexKey? {
|
||||
ensure(tag.has(1)) { return null }
|
||||
@@ -89,10 +94,11 @@ data class PTag(
|
||||
ensure(tag[1].length == 64) { return null }
|
||||
ensure(tag[2].isNotEmpty()) { return null }
|
||||
|
||||
val normalized = RelayUrlNormalizer.normalizeOrNull(tag[2])
|
||||
ensure(normalized != null) { return null }
|
||||
val hint = pickRelayHint(tag)
|
||||
|
||||
return PubKeyHint(tag[1], normalized)
|
||||
ensure(hint != null) { return null }
|
||||
|
||||
return PubKeyHint(tag[1], hint)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
@@ -20,12 +20,14 @@
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip10Notes.tags
|
||||
|
||||
import android.R.attr.tag
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer.Companion.isRelayUrl
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.events.GenericETag
|
||||
import com.vitorpamplona.quartz.nip19Bech32.entities.NEvent
|
||||
import com.vitorpamplona.quartz.utils.arrayOfNotNull
|
||||
@@ -87,67 +89,71 @@ data class MarkedETag(
|
||||
|
||||
@JvmStatic
|
||||
fun parse(tag: Array<String>): MarkedETag? {
|
||||
if (tag.size < TAG_SIZE || tag[0] != TAG_NAME) return null
|
||||
ensure(tag.has(2)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(tag[1].length == 64) { return null }
|
||||
ensure(tag[2].isNotEmpty()) { return null }
|
||||
|
||||
return MarkedETag(
|
||||
tag[ORDER_EVT_ID],
|
||||
RelayUrlNormalizer.normalizeOrNull(tag[ORDER_RELAY]),
|
||||
MARKER.parse(tag[ORDER_MARKER]),
|
||||
tag.getOrNull(ORDER_PUBKEY),
|
||||
eventId = tag[1],
|
||||
relayHint = pickRelayHint(tag),
|
||||
marker = pickMarker(tag),
|
||||
authorPubKeyHex = pickAuthor(tag),
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun parseId(tag: Array<String>): HexKey? {
|
||||
if (tag.size < TAG_SIZE || tag[0] != TAG_NAME) return null
|
||||
ensure(tag.has(2)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(tag[1].length == 64) { return null }
|
||||
|
||||
return tag[ORDER_EVT_ID]
|
||||
return tag[1]
|
||||
}
|
||||
|
||||
// simple case ["e", "id", "relay"]
|
||||
// empty tags ["e", "id", "relay", ""]
|
||||
// current root ["e", "id", "relay", "marker"]
|
||||
// current root ["e", "id", "relay", "marker", "pubkey"]
|
||||
// empty tags ["e", "id", "relay", "", "pubkey"]
|
||||
// pubkey marker ["e", "id", "relay", "pubkey"]
|
||||
// pubkey marker ["e", "id", "relay", "pubkey", "marker"]
|
||||
// pubkey marker ["e", "id", "pubkey"] // incorrect
|
||||
// current root ["e", "id", "marker"] // incorrect
|
||||
|
||||
@JvmStatic
|
||||
private fun pickRelayHint(tag: Array<String>): NormalizedRelayUrl? {
|
||||
if (tag.has(2) && tag[2].length > 7 && RelayUrlNormalizer.isRelayUrl(tag[2])) return RelayUrlNormalizer.normalizeOrNull(tag[2])
|
||||
if (tag.has(3) && tag[3].length > 7 && RelayUrlNormalizer.isRelayUrl(tag[3])) return RelayUrlNormalizer.normalizeOrNull(tag[3])
|
||||
if (tag.has(4) && tag[4].length > 7 && RelayUrlNormalizer.isRelayUrl(tag[4])) return RelayUrlNormalizer.normalizeOrNull(tag[4])
|
||||
return null
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
private fun pickAuthor(tag: Array<String>): HexKey? {
|
||||
if (tag.has(3) && tag[3].length == 64) return tag[3]
|
||||
if (tag.has(4) && tag[4].length == 64) return tag[4]
|
||||
if (tag.has(2) && tag[2].length == 64) return tag[2]
|
||||
return null
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
private fun pickMarker(tag: Array<String>): MARKER? {
|
||||
if (tag.has(3)) MARKER.parse(tag[3])?.let { return it }
|
||||
if (tag.has(4)) MARKER.parse(tag[4])?.let { return it }
|
||||
if (tag.has(2)) MARKER.parse(tag[2])?.let { return it }
|
||||
return null
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun parseAllThreadTags(tag: Array<String>): MarkedETag? =
|
||||
if (tag.size >= 2 && tag[0] == TAG_NAME) {
|
||||
if (tag.size <= 3) {
|
||||
// simple case ["e", "id", "relay"]
|
||||
MarkedETag(tag[1], tag.getOrNull(2)?.let { RelayUrlNormalizer.normalizeOrNull(it) }, null, null)
|
||||
} else if (tag.size == 4) {
|
||||
val relayHint = RelayUrlNormalizer.normalizeOrNull(tag[2])
|
||||
if (tag[3].isEmpty()) {
|
||||
// empty tags ["e", "id", "relay", ""]
|
||||
MarkedETag(tag[1], relayHint, null, null)
|
||||
} else if (tag[3].length == 64) {
|
||||
// updated case with pubkey instead of marker ["e", "id", "relay", "pubkey"]
|
||||
MarkedETag(tag[1], relayHint, null, tag[3])
|
||||
} else if (tag[3] == MARKER.ROOT.code) {
|
||||
// corrent root ["e", "id", "relay", "root"]
|
||||
MarkedETag(tag[1], relayHint, MARKER.ROOT)
|
||||
} else if (tag[3] == MARKER.REPLY.code) {
|
||||
// correct reply ["e", "id", "relay", "reply"]
|
||||
MarkedETag(tag[1], relayHint, MARKER.REPLY)
|
||||
} else {
|
||||
// ignore "mention" and "fork" markers
|
||||
null
|
||||
}
|
||||
} else {
|
||||
val relayHint = RelayUrlNormalizer.normalizeOrNull(tag[2])
|
||||
// tag.size >= 5
|
||||
if (tag[3].isEmpty()) {
|
||||
// empty tags ["e", "id", "relay", "", "pubkey"]
|
||||
MarkedETag(tag[1], relayHint, null, tag[4])
|
||||
} else if (tag[3].length == 64) {
|
||||
// updated case with pubkey instead of marker ["e", "id", "relay", "pubkey"]
|
||||
MarkedETag(tag[1], relayHint, null, tag[3])
|
||||
} else if (tag[3] == MARKER.ROOT.code) {
|
||||
// corrent root ["e", "id", "relay", "root"]
|
||||
MarkedETag(tag[1], relayHint, MARKER.ROOT, tag[4])
|
||||
} else if (tag[3] == MARKER.REPLY.code) {
|
||||
// correct reply ["e", "id", "relay", "reply"]
|
||||
MarkedETag(tag[1], relayHint, MARKER.REPLY, tag[4])
|
||||
} else {
|
||||
// ignore "mention" and "fork" markers
|
||||
null
|
||||
}
|
||||
}
|
||||
MarkedETag(
|
||||
eventId = tag[1],
|
||||
relayHint = pickRelayHint(tag),
|
||||
marker = pickMarker(tag),
|
||||
authorPubKeyHex = pickAuthor(tag),
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
@@ -187,9 +193,8 @@ data class MarkedETag(
|
||||
ensure(tag.has(2)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(tag[1].length == 64) { return null }
|
||||
ensure(tag[2].isNotEmpty()) { return null }
|
||||
|
||||
val hint = RelayUrlNormalizer.normalizeOrNull(tag[2])
|
||||
val hint = pickRelayHint(tag)
|
||||
ensure(hint != null) { return null }
|
||||
|
||||
return EventIdHint(tag[1], hint)
|
||||
@@ -197,15 +202,18 @@ data class MarkedETag(
|
||||
|
||||
@JvmStatic
|
||||
fun parseRoot(tag: Array<String>): MarkedETag? {
|
||||
if (tag.size < TAG_SIZE || tag[0] != TAG_NAME) return null
|
||||
if (tag[ORDER_MARKER] != MARKER.ROOT.code) return null
|
||||
ensure(tag.has(3)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(tag[1].length == 64) { return null }
|
||||
|
||||
val marker = pickMarker(tag)
|
||||
ensure(marker == MARKER.ROOT) { return null }
|
||||
|
||||
// ["e", id hex, relay hint, marker, pubkey]
|
||||
return MarkedETag(
|
||||
eventId = tag[ORDER_EVT_ID],
|
||||
relayHint = RelayUrlNormalizer.normalizeOrNull(tag[ORDER_RELAY]),
|
||||
marker = MARKER.ROOT,
|
||||
authorPubKeyHex = tag.getOrNull(ORDER_PUBKEY),
|
||||
eventId = tag[1],
|
||||
relayHint = pickRelayHint(tag),
|
||||
marker = marker,
|
||||
authorPubKeyHex = pickAuthor(tag),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -215,23 +223,25 @@ data class MarkedETag(
|
||||
@JvmStatic
|
||||
fun parseUnmarkedRoot(tag: Array<String>): MarkedETag? =
|
||||
if (tag.size in 2..3 && tag[0] == TAG_NAME) {
|
||||
MarkedETag(tag[1], tag.getOrNull(2)?.let { RelayUrlNormalizer.normalizeOrNull(it) }, MARKER.ROOT)
|
||||
MarkedETag(tag[1], pickRelayHint(tag), MARKER.ROOT)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun parseReply(tag: Array<String>): MarkedETag? {
|
||||
if (tag.size < TAG_SIZE || tag[0] != TAG_NAME) return null
|
||||
if (tag[ORDER_MARKER] != MARKER.REPLY.code) return null
|
||||
// ["e", id hex, relay hint, marker, pubkey]
|
||||
ensure(tag.has(3)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(tag[1].length == 64) { return null }
|
||||
|
||||
val marker = pickMarker(tag)
|
||||
ensure(marker == MARKER.REPLY) { return null }
|
||||
|
||||
return MarkedETag(
|
||||
tag[ORDER_EVT_ID],
|
||||
RelayUrlNormalizer.normalizeOrNull(tag[ORDER_RELAY]),
|
||||
MARKER.REPLY,
|
||||
tag.getOrNull(
|
||||
ORDER_PUBKEY,
|
||||
),
|
||||
eventId = tag[1],
|
||||
relayHint = pickRelayHint(tag),
|
||||
marker = marker,
|
||||
authorPubKeyHex = pickAuthor(tag),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -241,17 +251,21 @@ data class MarkedETag(
|
||||
@JvmStatic
|
||||
fun parseUnmarkedReply(tag: Array<String>): MarkedETag? =
|
||||
if (tag.size in 2..3 && tag[0] == TAG_NAME) {
|
||||
MarkedETag(tag[1], tag.getOrNull(2)?.let { RelayUrlNormalizer.normalizeOrNull(it) }, MARKER.REPLY)
|
||||
MarkedETag(tag[1], pickRelayHint(tag), MARKER.REPLY)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun parseRootId(tag: Array<String>): HexKey? {
|
||||
if (tag.size < TAG_SIZE || tag[0] != TAG_NAME) return null
|
||||
if (tag[ORDER_MARKER] != MARKER.ROOT.code) return null
|
||||
// ["e", id hex, relay hint, marker, pubkey]
|
||||
return tag[ORDER_EVT_ID]
|
||||
ensure(tag.has(3)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(tag[1].length == 64) { return null }
|
||||
|
||||
val marker = pickMarker(tag)
|
||||
ensure(marker == MARKER.ROOT) { return null }
|
||||
|
||||
return tag[1]
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
@@ -20,9 +20,11 @@
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip18Reposts.quotes
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint
|
||||
import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address
|
||||
import com.vitorpamplona.quartz.utils.ensure
|
||||
@@ -38,16 +40,28 @@ interface QTag {
|
||||
ensure(tag.has(1)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
|
||||
val relayHint = tag.getOrNull(2)?.let { RelayUrlNormalizer.normalizeOrNull(it) }
|
||||
val relayHint = pickRelayHint(tag)
|
||||
|
||||
return if (tag[1].length == 64) {
|
||||
QEventTag(tag[1], relayHint, tag.getOrNull(3))
|
||||
QEventTag(tag[1], relayHint, pickAuthor(tag))
|
||||
} else {
|
||||
val address = Address.parse(tag[1]) ?: return null
|
||||
QAddressableTag(address, relayHint)
|
||||
}
|
||||
}
|
||||
|
||||
private fun pickRelayHint(tag: Array<String>): NormalizedRelayUrl? {
|
||||
if (tag.has(2) && tag[2].length > 7 && RelayUrlNormalizer.isRelayUrl(tag[2])) return RelayUrlNormalizer.normalizeOrNull(tag[2])
|
||||
if (tag.has(3) && tag[3].length > 7 && RelayUrlNormalizer.isRelayUrl(tag[3])) return RelayUrlNormalizer.normalizeOrNull(tag[3])
|
||||
return null
|
||||
}
|
||||
|
||||
private fun pickAuthor(tag: Array<String>): HexKey? {
|
||||
if (tag.has(2) && tag[2].length == 64) return tag[2]
|
||||
if (tag.has(3) && tag[3].length == 64) return tag[3]
|
||||
return null
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun parseKey(tag: Array<String>): String? {
|
||||
ensure(tag.has(1)) { return null }
|
||||
@@ -62,7 +76,7 @@ interface QTag {
|
||||
ensure(tag[1].length == 64) { return null }
|
||||
ensure(tag[2].isNotEmpty()) { return null }
|
||||
|
||||
val relayHint = RelayUrlNormalizer.normalizeOrNull(tag[2])
|
||||
val relayHint = pickRelayHint(tag)
|
||||
ensure(relayHint != null) { return null }
|
||||
|
||||
return EventIdHint(tag[1], relayHint)
|
||||
@@ -76,7 +90,7 @@ interface QTag {
|
||||
ensure(tag[2].isNotEmpty()) { return null }
|
||||
ensure(!tag[1].contains(':')) { return null }
|
||||
|
||||
val relayHint = RelayUrlNormalizer.normalizeOrNull(tag[2])
|
||||
val relayHint = pickRelayHint(tag)
|
||||
ensure(relayHint != null) { return null }
|
||||
|
||||
return AddressHint(tag[1], relayHint)
|
||||
|
Reference in New Issue
Block a user