mirror of
https://github.com/greenart7c3/Amber.git
synced 2026-10-05 19:08:23 +00:00
Merge #ce483d5b: Fix nostrconnect parser corrupting param values that c…
Fix nostrconnect parser corrupting param values that contain = nostr:nevent1qqsvujpatdel7f9l7cn0zzux8pwcpyfajuffs0ma3ajyfqcwh4s6x0gpz3mhxue69uhhyetvv9ujumn8d96zuer9wcy06jya PR-Author: greenart7c3 nostr:npub1w4uswmv6lu9yel005l3qgheysmr7tk9uvwluddznju3nuxalevvs2d0jr5 PR description: Param values such as base64 secrets with padding (XQUdha4rjh_gjAgHN8X5yg==) were split on every = and rejoined with joinToString's default ", " separator, so the connect response returned "XQUdha4rjh_gjAgHN8X5yg, , " instead of the original secret and NDK-based clients failed their secret check. Params are now split on the first = only, so values containing = round-trip unchanged. Also joins the query-string pieces after ? without a separator, so unencoded ? characters no longer corrupt the query. Adds unit tests for the splitParam helper, including the base64-padding regression case. Fixes https://github.com/greenart7c3/Amber/issues/526
This commit is contained in:
@@ -18,6 +18,11 @@ import java.util.UUID
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
object NostrConnectUtils {
|
||||
/**
|
||||
* Splits a query parameter into its name and value on the first `=` only,
|
||||
* so values that contain `=` (e.g. base64 padding like "XQUdha4rjh_gjAgHN8X5yg==") are preserved.
|
||||
*/
|
||||
fun splitParam(param: String): Pair<String, String> = param.substringBefore("=") to param.substringAfter("=", "")
|
||||
private fun metaDataFromJson(json: String): BunkerMetadata = BunkerMetadata.mapper.readValue(json, BunkerMetadata::class.java)
|
||||
|
||||
fun getIntentFromNostrConnect(
|
||||
@@ -36,16 +41,12 @@ object NostrConnectUtils {
|
||||
var url = ""
|
||||
var image = ""
|
||||
val pubKey = split.first()
|
||||
val parsedData = IntentUtils.decodeData(split.drop(1).joinToString { it })
|
||||
val parsedData = IntentUtils.decodeData(split.drop(1).joinToString("") { it })
|
||||
val splitParsedData = parsedData.split("&")
|
||||
val permissions = mutableListOf<Permission>()
|
||||
var nostrConnectSecret = ""
|
||||
splitParsedData.forEach {
|
||||
val internalSplit = it.split("=")
|
||||
val paramName = internalSplit.first()
|
||||
val json = internalSplit.mapIndexedNotNull { index, s ->
|
||||
if (index == 0) null else s
|
||||
}.joinToString { data -> data }
|
||||
val (paramName, json) = splitParam(it)
|
||||
if (paramName == "relay") {
|
||||
val relayUrl = RelayUrlNormalizer.normalizeOrNull(json)
|
||||
if (relayUrl != null) {
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.greenart7c3.nostrsigner.service
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class NostrConnectUtilsTest {
|
||||
|
||||
// --- values that contain `=` (issue #526) ---
|
||||
|
||||
@Test
|
||||
fun `base64 secret with padding is preserved`() {
|
||||
val (name, value) = NostrConnectUtils.splitParam("secret=XQUdha4rjh_gjAgHN8X5yg==")
|
||||
assertEquals("secret", name)
|
||||
assertEquals("XQUdha4rjh_gjAgHN8X5yg==", value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `value with multiple equals signs is preserved`() {
|
||||
val (name, value) = NostrConnectUtils.splitParam("secret=YQ==Zm9v")
|
||||
assertEquals("secret", name)
|
||||
assertEquals("YQ==Zm9v", value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `url encoded relay value is not corrupted`() {
|
||||
val (name, value) = NostrConnectUtils.splitParam("relay=wss%3A%2F%2Frelay.primal.net")
|
||||
assertEquals("relay", name)
|
||||
assertEquals("wss%3A%2F%2Frelay.primal.net", value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `perms value is preserved`() {
|
||||
val (name, value) = NostrConnectUtils.splitParam("perms=nip04_encrypt,nip44_decrypt,sign_event:1")
|
||||
assertEquals("perms", name)
|
||||
assertEquals("nip04_encrypt,nip44_decrypt,sign_event:1", value)
|
||||
}
|
||||
|
||||
// --- degenerate inputs keep the previous behavior ---
|
||||
|
||||
@Test
|
||||
fun `parameter without equals has empty value`() {
|
||||
val (name, value) = NostrConnectUtils.splitParam("flag")
|
||||
assertEquals("flag", name)
|
||||
assertEquals("", value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parameter with empty value returns empty string`() {
|
||||
val (name, value) = NostrConnectUtils.splitParam("secret=")
|
||||
assertEquals("secret", name)
|
||||
assertEquals("", value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `empty parameter returns empty name and value`() {
|
||||
val (name, value) = NostrConnectUtils.splitParam("")
|
||||
assertEquals("", name)
|
||||
assertEquals("", value)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user