Fixes bug when verifying the checksum of LNURLs (bech32) in uppercase.

This commit is contained in:
Vitor Pamplona 2023-09-14 13:46:29 -04:00
parent cb69d056b8
commit 310db1008e
5 changed files with 58 additions and 26 deletions

View File

@ -5,16 +5,15 @@ import androidx.compose.runtime.Stable
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.distinctUntilChanged
import androidx.lifecycle.map
import com.vitorpamplona.amethyst.service.NostrSingleUserDataSource
import com.vitorpamplona.amethyst.service.checkNotInMainThread
import com.vitorpamplona.amethyst.service.relays.EOSETime
import com.vitorpamplona.amethyst.service.relays.Relay
import com.vitorpamplona.amethyst.ui.components.BundledUpdate
import com.vitorpamplona.amethyst.ui.note.toShortenHex
import com.vitorpamplona.quartz.encoders.Bech32
import com.vitorpamplona.quartz.encoders.Hex
import com.vitorpamplona.quartz.encoders.HexKey
import com.vitorpamplona.quartz.encoders.Lud06
import com.vitorpamplona.quartz.encoders.toNpub
import com.vitorpamplona.quartz.events.BookmarkListEvent
import com.vitorpamplona.quartz.events.ChatroomKey
@ -27,9 +26,6 @@ import com.vitorpamplona.quartz.events.toImmutableListOfLists
import kotlinx.collections.immutable.persistentSetOf
import kotlinx.coroutines.Dispatchers
import java.math.BigDecimal
import java.util.regex.Pattern
val lnurlpPattern = Pattern.compile("(?i:http|https):\\/\\/((.+)\\/)*\\.well-known\\/lnurlp\\/(.*)")
@Stable
class User(val pubkeyHex: String) {
@ -268,19 +264,11 @@ class User(val pubkeyHex: String) {
info?.updatedMetadataAt = latestMetadata.createdAt
info?.tags = latestMetadata.tags.toImmutableListOfLists()
if (newUserInfo.lud16.isNullOrBlank() && newUserInfo.lud06?.lowercase()?.startsWith("lnurl") == true) {
try {
val url = String(Bech32.decodeBytes(newUserInfo.lud06!!, false).second)
val matcher = lnurlpPattern.matcher(url)
while (matcher.find()) {
val domain = matcher.group(2)
val username = matcher.group(3)
info?.lud16 = "$username@$domain"
if (newUserInfo.lud16.isNullOrBlank()) {
info?.lud06?.let {
if (it.lowercase().startsWith("lnurl")) {
info?.lud16 = Lud06().toLud16(it)
}
} catch (t: Throwable) {
// Doesn't create errors.
}
}

View File

@ -4,8 +4,8 @@ import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.vitorpamplona.amethyst.BuildConfig
import com.vitorpamplona.amethyst.service.HttpClient
import com.vitorpamplona.amethyst.service.checkNotInMainThread
import com.vitorpamplona.quartz.encoders.Bech32
import com.vitorpamplona.quartz.encoders.LnInvoiceUtil
import com.vitorpamplona.quartz.encoders.Lud06
import com.vitorpamplona.quartz.encoders.toLnUrl
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@ -27,11 +27,7 @@ class LightningAddressResolver() {
}
if (lnaddress.lowercase().startsWith("lnurl")) {
return try {
String(Bech32.decodeBytes(lnaddress, false).second)
} catch (e: Exception) {
null
}
return Lud06().toLnUrlp(lnaddress)
}
return null

View File

@ -69,14 +69,14 @@ object Bech32 {
values.forEach { v ->
val b = chk shr 25
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]
}
}
values1.forEach { v ->
val b = chk shr 25
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]
}
}
@ -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" }
val data = Array(bech32.length - pos - 1) {

View File

@ -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
}
}
}

View File

@ -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))
}
}