mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-09-26 22:56:30 +02:00
Fixes bug when verifying the checksum of LNURLs (bech32) in uppercase.
This commit is contained in:
@@ -5,16 +5,15 @@ import androidx.compose.runtime.Stable
|
|||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MediatorLiveData
|
import androidx.lifecycle.MediatorLiveData
|
||||||
import androidx.lifecycle.distinctUntilChanged
|
import androidx.lifecycle.distinctUntilChanged
|
||||||
import androidx.lifecycle.map
|
|
||||||
import com.vitorpamplona.amethyst.service.NostrSingleUserDataSource
|
import com.vitorpamplona.amethyst.service.NostrSingleUserDataSource
|
||||||
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
||||||
import com.vitorpamplona.amethyst.service.relays.EOSETime
|
import com.vitorpamplona.amethyst.service.relays.EOSETime
|
||||||
import com.vitorpamplona.amethyst.service.relays.Relay
|
import com.vitorpamplona.amethyst.service.relays.Relay
|
||||||
import com.vitorpamplona.amethyst.ui.components.BundledUpdate
|
import com.vitorpamplona.amethyst.ui.components.BundledUpdate
|
||||||
import com.vitorpamplona.amethyst.ui.note.toShortenHex
|
import com.vitorpamplona.amethyst.ui.note.toShortenHex
|
||||||
import com.vitorpamplona.quartz.encoders.Bech32
|
|
||||||
import com.vitorpamplona.quartz.encoders.Hex
|
import com.vitorpamplona.quartz.encoders.Hex
|
||||||
import com.vitorpamplona.quartz.encoders.HexKey
|
import com.vitorpamplona.quartz.encoders.HexKey
|
||||||
|
import com.vitorpamplona.quartz.encoders.Lud06
|
||||||
import com.vitorpamplona.quartz.encoders.toNpub
|
import com.vitorpamplona.quartz.encoders.toNpub
|
||||||
import com.vitorpamplona.quartz.events.BookmarkListEvent
|
import com.vitorpamplona.quartz.events.BookmarkListEvent
|
||||||
import com.vitorpamplona.quartz.events.ChatroomKey
|
import com.vitorpamplona.quartz.events.ChatroomKey
|
||||||
@@ -27,9 +26,6 @@ import com.vitorpamplona.quartz.events.toImmutableListOfLists
|
|||||||
import kotlinx.collections.immutable.persistentSetOf
|
import kotlinx.collections.immutable.persistentSetOf
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.util.regex.Pattern
|
|
||||||
|
|
||||||
val lnurlpPattern = Pattern.compile("(?i:http|https):\\/\\/((.+)\\/)*\\.well-known\\/lnurlp\\/(.*)")
|
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
class User(val pubkeyHex: String) {
|
class User(val pubkeyHex: String) {
|
||||||
@@ -268,19 +264,11 @@ class User(val pubkeyHex: String) {
|
|||||||
info?.updatedMetadataAt = latestMetadata.createdAt
|
info?.updatedMetadataAt = latestMetadata.createdAt
|
||||||
info?.tags = latestMetadata.tags.toImmutableListOfLists()
|
info?.tags = latestMetadata.tags.toImmutableListOfLists()
|
||||||
|
|
||||||
if (newUserInfo.lud16.isNullOrBlank() && newUserInfo.lud06?.lowercase()?.startsWith("lnurl") == true) {
|
if (newUserInfo.lud16.isNullOrBlank()) {
|
||||||
try {
|
info?.lud06?.let {
|
||||||
val url = String(Bech32.decodeBytes(newUserInfo.lud06!!, false).second)
|
if (it.lowercase().startsWith("lnurl")) {
|
||||||
|
info?.lud16 = Lud06().toLud16(it)
|
||||||
val matcher = lnurlpPattern.matcher(url)
|
|
||||||
while (matcher.find()) {
|
|
||||||
val domain = matcher.group(2)
|
|
||||||
val username = matcher.group(3)
|
|
||||||
|
|
||||||
info?.lud16 = "$username@$domain"
|
|
||||||
}
|
}
|
||||||
} catch (t: Throwable) {
|
|
||||||
// Doesn't create errors.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -4,8 +4,8 @@ import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
|||||||
import com.vitorpamplona.amethyst.BuildConfig
|
import com.vitorpamplona.amethyst.BuildConfig
|
||||||
import com.vitorpamplona.amethyst.service.HttpClient
|
import com.vitorpamplona.amethyst.service.HttpClient
|
||||||
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
||||||
import com.vitorpamplona.quartz.encoders.Bech32
|
|
||||||
import com.vitorpamplona.quartz.encoders.LnInvoiceUtil
|
import com.vitorpamplona.quartz.encoders.LnInvoiceUtil
|
||||||
|
import com.vitorpamplona.quartz.encoders.Lud06
|
||||||
import com.vitorpamplona.quartz.encoders.toLnUrl
|
import com.vitorpamplona.quartz.encoders.toLnUrl
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
@@ -27,11 +27,7 @@ class LightningAddressResolver() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (lnaddress.lowercase().startsWith("lnurl")) {
|
if (lnaddress.lowercase().startsWith("lnurl")) {
|
||||||
return try {
|
return Lud06().toLnUrlp(lnaddress)
|
||||||
String(Bech32.decodeBytes(lnaddress, false).second)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
|
@@ -69,14 +69,14 @@ object Bech32 {
|
|||||||
values.forEach { v ->
|
values.forEach { v ->
|
||||||
val b = chk shr 25
|
val b = chk shr 25
|
||||||
chk = ((chk and 0x1ffffff) shl 5) xor v.toInt()
|
chk = ((chk and 0x1ffffff) shl 5) xor v.toInt()
|
||||||
for (i in 0..5) {
|
for (i in 0..4) {
|
||||||
if (((b shr i) and 1) != 0) chk = chk xor GEN[i]
|
if (((b shr i) and 1) != 0) chk = chk xor GEN[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
values1.forEach { v ->
|
values1.forEach { v ->
|
||||||
val b = chk shr 25
|
val b = chk shr 25
|
||||||
chk = ((chk and 0x1ffffff) shl 5) xor v.toInt()
|
chk = ((chk and 0x1ffffff) shl 5) xor v.toInt()
|
||||||
for (i in 0..5) {
|
for (i in 0..4) {
|
||||||
if (((b shr i) and 1) != 0) chk = chk xor GEN[i]
|
if (((b shr i) and 1) != 0) chk = chk xor GEN[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,7 +129,7 @@ object Bech32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val hrp = bech32.take(pos)
|
val hrp = bech32.take(pos).lowercase() // strings must be lower case
|
||||||
require(hrp.length in 1..83) { "hrp must contain 1 to 83 characters" }
|
require(hrp.length in 1..83) { "hrp must contain 1 to 83 characters" }
|
||||||
|
|
||||||
val data = Array(bech32.length - pos - 1) {
|
val data = Array(bech32.length - pos - 1) {
|
||||||
|
@@ -0,0 +1,35 @@
|
|||||||
|
package com.vitorpamplona.quartz.encoders
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
|
val lnurlpPattern = Pattern.compile("(?i:http|https):\\/\\/((.+)\\/)*\\.well-known\\/lnurlp\\/(.*)")
|
||||||
|
|
||||||
|
class Lud06 {
|
||||||
|
fun toLud16(str: String): String? {
|
||||||
|
return try {
|
||||||
|
val url = toLnUrlp(str)
|
||||||
|
|
||||||
|
val matcher = lnurlpPattern.matcher(url)
|
||||||
|
matcher.find()
|
||||||
|
val domain = matcher.group(2)
|
||||||
|
val username = matcher.group(3)
|
||||||
|
|
||||||
|
"$username@$domain"
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
t.printStackTrace()
|
||||||
|
Log.w("Lud06ToLud16","Fail to convert LUD06 to LUD16",t)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toLnUrlp(str: String): String? {
|
||||||
|
return try {
|
||||||
|
String(Bech32.decodeBytes(str, false).second)
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
t.printStackTrace()
|
||||||
|
Log.w("Lud06ToLud16","Fail to convert LUD06 to LUD16",t)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,13 @@
|
|||||||
|
package com.vitorpamplona.quartz.encoders
|
||||||
|
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class Lud06Test {
|
||||||
|
val lnTips = "LNURL1DP68GURN8GHJ7MRW9E6XJURN9UH8WETVDSKKKMN0WAHZ7MRWW4EXCUP0XPURXEFEX9SKGCT9V5ER2V33X4NRGP2NE42"
|
||||||
|
@Test()
|
||||||
|
fun parseLnUrlp() {
|
||||||
|
assertEquals("https://ln.tips/.well-known/lnurlp/0x3e91adaee25215f4", Lud06().toLnUrlp(lnTips))
|
||||||
|
assertEquals("0x3e91adaee25215f4@ln.tips", Lud06().toLud16(lnTips))
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user