mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-11 08:47:33 +00:00
fix(cli): nak-compatible bunker — percent-encoded URIs + get_relays
Close the NIP-46 interop gap against the real nak binary: - `Identity.fromBunkerUri` now URL-decodes the relay/secret params. nak emits `bunker://<pk>?relay=wss%3A%2F%2F…&secret=…`; without decoding, `amy login` of a nak bunker URI produced a broken relay and never connected. (This was the one real break — found by testing vs nak.) - `amy bunker` now percent-encodes the relay/secret in the URI it prints, matching nak's output format. - `amy bunker` implements `get_relays` (returns its relay set), so nak clients that probe it get a proper reply instead of an error. Verified end-to-end with `go install`-built nak over relay.damus.io, both directions: - `amy login bunker://` ⇄ `nak bunker`: amy signs, event authored by nak's key, signature valid. - `nak event --sec bunker://<amy>` ⇄ `amy bunker`: nak signs through amy, event authored by amy's key; amy logs connect→ok, sign_event→ok. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011SapGdtAc1j7woifoCZ9fY
This commit is contained in:
@@ -92,9 +92,12 @@ data class Identity(
|
||||
parts.getOrNull(1)?.split("&")?.forEach { param ->
|
||||
val kv = param.split("=", limit = 2)
|
||||
if (kv.size < 2) return@forEach
|
||||
// Relay/secret params are percent-encoded by spec-compliant
|
||||
// emitters (nak does: `relay=wss%3A%2F%2F…`), so decode them.
|
||||
val value = java.net.URLDecoder.decode(kv[1], "UTF-8")
|
||||
when (kv[0]) {
|
||||
"relay" -> relays.add(kv[1])
|
||||
"secret" -> secret = kv[1]
|
||||
"relay" -> relays.add(value)
|
||||
"secret" -> secret = value
|
||||
}
|
||||
}
|
||||
require(relays.isNotEmpty()) { "bunker uri must carry at least one relay" }
|
||||
|
||||
@@ -34,6 +34,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequest
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequestConnect
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequestGetPublicKey
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequestGetRelays
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequestNip04Decrypt
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequestNip04Encrypt
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequestNip44Decrypt
|
||||
@@ -46,9 +47,11 @@ import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponseDecrypt
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponseEncrypt
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponseError
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponseEvent
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponseGetRelays
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponsePong
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponsePublicKey
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.NostrConnectEvent
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.ReadWrite
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
@@ -93,11 +96,13 @@ object BunkerCommand {
|
||||
val secret = args.flag("secret") ?: KeyPair().privKey!!.toHexKey().take(32)
|
||||
val self = ctx.identity.pubKeyHex
|
||||
|
||||
// Percent-encode params (spec/nak convention: relay=wss%3A%2F%2F…).
|
||||
val enc = { s: String -> java.net.URLEncoder.encode(s, "UTF-8") }
|
||||
val uri =
|
||||
buildString {
|
||||
append("bunker://").append(self)
|
||||
append("?").append(relays.joinToString("&") { "relay=${it.url}" })
|
||||
append("&secret=").append(secret)
|
||||
append("?").append(relays.joinToString("&") { "relay=${enc(it.url)}" })
|
||||
append("&secret=").append(enc(secret))
|
||||
}
|
||||
Output.emit(
|
||||
mapOf(
|
||||
@@ -165,6 +170,7 @@ object BunkerCommand {
|
||||
BunkerResponseError(request.id, "invalid secret")
|
||||
}
|
||||
is BunkerRequestGetPublicKey -> BunkerResponsePublicKey(request.id, signer.pubKey)
|
||||
is BunkerRequestGetRelays -> BunkerResponseGetRelays(request.id, relays.associate { it.url to ReadWrite(read = true, write = true) })
|
||||
is BunkerRequestPing -> BunkerResponsePong(request.id)
|
||||
is BunkerRequestSign -> {
|
||||
val signed = signer.sign<Event>(request.event.createdAt, request.event.kind, request.event.tags, request.event.content)
|
||||
|
||||
Reference in New Issue
Block a user