fix(quartz): connect() returns Unit, caller calls getPublicKey separately
Per Amber maintainer: connect never returns a pubkey — response is "ack" or the secret string. Rewrote ConnectResponse.parse() to check result/error fields directly on base BunkerResponse (matching Jackson deserialization). connect() is now a pure protocol handshake; callers call getPublicKey() separately as a domain concern. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+13
-23
@@ -21,33 +21,23 @@
|
||||
package com.vitorpamplona.quartz.nip46RemoteSigner.signer
|
||||
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponse
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponseAck
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponseError
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponsePublicKey
|
||||
|
||||
class ConnectResponse {
|
||||
companion object {
|
||||
fun parse(response: BunkerResponse): SignerResult.RequestAddressed<ConnectResult> =
|
||||
when (response) {
|
||||
is BunkerResponsePublicKey -> {
|
||||
SignerResult.RequestAddressed.Successful(ConnectResult.PubKey(response.pubkey))
|
||||
}
|
||||
|
||||
is BunkerResponseAck -> {
|
||||
SignerResult.RequestAddressed.Successful(ConnectResult.Ack)
|
||||
}
|
||||
|
||||
is BunkerResponseError -> {
|
||||
if (response.error?.contains("already connected", ignoreCase = true) == true) {
|
||||
SignerResult.RequestAddressed.Successful(ConnectResult.AlreadyConnected)
|
||||
} else {
|
||||
SignerResult.RequestAddressed.Rejected()
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
SignerResult.RequestAddressed.ReceivedButCouldNotPerform()
|
||||
fun parse(response: BunkerResponse): SignerResult.RequestAddressed<ConnectResult> {
|
||||
if (response.error != null) {
|
||||
return if (response.error.contains("already connected", ignoreCase = true)) {
|
||||
SignerResult.RequestAddressed.Successful(ConnectResult.AlreadyConnected)
|
||||
} else {
|
||||
SignerResult.RequestAddressed.Rejected()
|
||||
}
|
||||
}
|
||||
|
||||
if (response.result != null) {
|
||||
return SignerResult.RequestAddressed.Successful(ConnectResult.Ack)
|
||||
}
|
||||
|
||||
return SignerResult.RequestAddressed.ReceivedButCouldNotPerform()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-13
@@ -220,7 +220,7 @@ class NostrSignerRemote(
|
||||
throw convertExceptions("Could not ping", result)
|
||||
}
|
||||
|
||||
suspend fun connect(): HexKey {
|
||||
suspend fun connect() {
|
||||
val result =
|
||||
manager.launchWaitAndParse(
|
||||
bunkerRequestBuilder = {
|
||||
@@ -233,19 +233,11 @@ class NostrSignerRemote(
|
||||
parser = ConnectResponse::parse,
|
||||
)
|
||||
|
||||
return when (result) {
|
||||
is SignerResult.RequestAddressed.Successful<ConnectResult> -> {
|
||||
when (val r = result.result) {
|
||||
is ConnectResult.PubKey -> r.pubkey
|
||||
is ConnectResult.Ack -> getPublicKey()
|
||||
is ConnectResult.AlreadyConnected -> getPublicKey()
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
throw convertExceptions("Could not connect", result)
|
||||
}
|
||||
if (result is SignerResult.RequestAddressed.Successful<ConnectResult>) {
|
||||
return
|
||||
}
|
||||
|
||||
throw convertExceptions("Could not connect", result)
|
||||
}
|
||||
|
||||
suspend fun getPublicKey(): HexKey {
|
||||
|
||||
-4
@@ -69,10 +69,6 @@ data class PublicKeyResult(
|
||||
) : IResult
|
||||
|
||||
sealed interface ConnectResult : IResult {
|
||||
data class PubKey(
|
||||
val pubkey: String,
|
||||
) : ConnectResult
|
||||
|
||||
data object Ack : ConnectResult
|
||||
|
||||
data object AlreadyConnected : ConnectResult
|
||||
|
||||
+17
-16
@@ -23,6 +23,7 @@ package com.vitorpamplona.quartz.nip46RemoteSigner.signer
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponse
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponseAck
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponseDecrypt
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponseEncrypt
|
||||
@@ -37,20 +38,20 @@ import kotlin.test.assertIs
|
||||
|
||||
class ResponseParserTest {
|
||||
// --- ConnectResponse ---
|
||||
|
||||
@Test
|
||||
fun connectParsePubKey() {
|
||||
val hex = "a".repeat(64)
|
||||
val response = BunkerResponsePublicKey("req-0", hex)
|
||||
val result = ConnectResponse.parse(response)
|
||||
assertIs<SignerResult.RequestAddressed.Successful<ConnectResult>>(result)
|
||||
assertIs<ConnectResult.PubKey>(result.result)
|
||||
assertEquals(hex, (result.result as ConnectResult.PubKey).pubkey)
|
||||
}
|
||||
// connect never returns a pubkey — it's "ack" or the secret string.
|
||||
// Tests use base BunkerResponse to match production deserialization behavior.
|
||||
|
||||
@Test
|
||||
fun connectParseAck() {
|
||||
val response = BunkerResponseAck("req-0")
|
||||
val response = BunkerResponse("req-0", "ack", null)
|
||||
val result = ConnectResponse.parse(response)
|
||||
assertIs<SignerResult.RequestAddressed.Successful<ConnectResult>>(result)
|
||||
assertIs<ConnectResult.Ack>(result.result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectParseSecret() {
|
||||
val response = BunkerResponse("req-0", "my-secret-token", null)
|
||||
val result = ConnectResponse.parse(response)
|
||||
assertIs<SignerResult.RequestAddressed.Successful<ConnectResult>>(result)
|
||||
assertIs<ConnectResult.Ack>(result.result)
|
||||
@@ -58,7 +59,7 @@ class ResponseParserTest {
|
||||
|
||||
@Test
|
||||
fun connectParseAlreadyConnected() {
|
||||
val response = BunkerResponseError("req-0", "already connected")
|
||||
val response = BunkerResponse("req-0", null, "already connected")
|
||||
val result = ConnectResponse.parse(response)
|
||||
assertIs<SignerResult.RequestAddressed.Successful<ConnectResult>>(result)
|
||||
assertIs<ConnectResult.AlreadyConnected>(result.result)
|
||||
@@ -66,7 +67,7 @@ class ResponseParserTest {
|
||||
|
||||
@Test
|
||||
fun connectParseAlreadyConnectedCaseInsensitive() {
|
||||
val response = BunkerResponseError("req-0", "Already Connected")
|
||||
val response = BunkerResponse("req-0", null, "Already Connected")
|
||||
val result = ConnectResponse.parse(response)
|
||||
assertIs<SignerResult.RequestAddressed.Successful<ConnectResult>>(result)
|
||||
assertIs<ConnectResult.AlreadyConnected>(result.result)
|
||||
@@ -74,14 +75,14 @@ class ResponseParserTest {
|
||||
|
||||
@Test
|
||||
fun connectParseRealError() {
|
||||
val response = BunkerResponseError("req-0", "unauthorized")
|
||||
val response = BunkerResponse("req-0", null, "unauthorized")
|
||||
val result = ConnectResponse.parse(response)
|
||||
assertIs<SignerResult.RequestAddressed.Rejected<ConnectResult>>(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectParseUnexpected() {
|
||||
val response = BunkerResponsePong("req-0")
|
||||
fun connectParseNoResultNoError() {
|
||||
val response = BunkerResponse("req-0", null, null)
|
||||
val result = ConnectResponse.parse(response)
|
||||
assertIs<SignerResult.RequestAddressed.ReceivedButCouldNotPerform<ConnectResult>>(result)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user