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
|
package com.vitorpamplona.quartz.nip46RemoteSigner.signer
|
||||||
|
|
||||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponse
|
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 {
|
class ConnectResponse {
|
||||||
companion object {
|
companion object {
|
||||||
fun parse(response: BunkerResponse): SignerResult.RequestAddressed<ConnectResult> =
|
fun parse(response: BunkerResponse): SignerResult.RequestAddressed<ConnectResult> {
|
||||||
when (response) {
|
if (response.error != null) {
|
||||||
is BunkerResponsePublicKey -> {
|
return if (response.error.contains("already connected", ignoreCase = true)) {
|
||||||
SignerResult.RequestAddressed.Successful(ConnectResult.PubKey(response.pubkey))
|
SignerResult.RequestAddressed.Successful(ConnectResult.AlreadyConnected)
|
||||||
}
|
} else {
|
||||||
|
SignerResult.RequestAddressed.Rejected()
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
throw convertExceptions("Could not ping", result)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun connect(): HexKey {
|
suspend fun connect() {
|
||||||
val result =
|
val result =
|
||||||
manager.launchWaitAndParse(
|
manager.launchWaitAndParse(
|
||||||
bunkerRequestBuilder = {
|
bunkerRequestBuilder = {
|
||||||
@@ -233,19 +233,11 @@ class NostrSignerRemote(
|
|||||||
parser = ConnectResponse::parse,
|
parser = ConnectResponse::parse,
|
||||||
)
|
)
|
||||||
|
|
||||||
return when (result) {
|
if (result is SignerResult.RequestAddressed.Successful<ConnectResult>) {
|
||||||
is SignerResult.RequestAddressed.Successful<ConnectResult> -> {
|
return
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw convertExceptions("Could not connect", result)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getPublicKey(): HexKey {
|
suspend fun getPublicKey(): HexKey {
|
||||||
|
|||||||
-4
@@ -69,10 +69,6 @@ data class PublicKeyResult(
|
|||||||
) : IResult
|
) : IResult
|
||||||
|
|
||||||
sealed interface ConnectResult : IResult {
|
sealed interface ConnectResult : IResult {
|
||||||
data class PubKey(
|
|
||||||
val pubkey: String,
|
|
||||||
) : ConnectResult
|
|
||||||
|
|
||||||
data object Ack : ConnectResult
|
data object Ack : ConnectResult
|
||||||
|
|
||||||
data object AlreadyConnected : 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.core.Event
|
||||||
import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair
|
import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair
|
||||||
import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal
|
import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal
|
||||||
|
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponse
|
||||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponseAck
|
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponseAck
|
||||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponseDecrypt
|
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponseDecrypt
|
||||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponseEncrypt
|
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponseEncrypt
|
||||||
@@ -37,20 +38,20 @@ import kotlin.test.assertIs
|
|||||||
|
|
||||||
class ResponseParserTest {
|
class ResponseParserTest {
|
||||||
// --- ConnectResponse ---
|
// --- ConnectResponse ---
|
||||||
|
// connect never returns a pubkey — it's "ack" or the secret string.
|
||||||
@Test
|
// Tests use base BunkerResponse to match production deserialization behavior.
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun connectParseAck() {
|
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)
|
val result = ConnectResponse.parse(response)
|
||||||
assertIs<SignerResult.RequestAddressed.Successful<ConnectResult>>(result)
|
assertIs<SignerResult.RequestAddressed.Successful<ConnectResult>>(result)
|
||||||
assertIs<ConnectResult.Ack>(result.result)
|
assertIs<ConnectResult.Ack>(result.result)
|
||||||
@@ -58,7 +59,7 @@ class ResponseParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun connectParseAlreadyConnected() {
|
fun connectParseAlreadyConnected() {
|
||||||
val response = BunkerResponseError("req-0", "already connected")
|
val response = BunkerResponse("req-0", null, "already connected")
|
||||||
val result = ConnectResponse.parse(response)
|
val result = ConnectResponse.parse(response)
|
||||||
assertIs<SignerResult.RequestAddressed.Successful<ConnectResult>>(result)
|
assertIs<SignerResult.RequestAddressed.Successful<ConnectResult>>(result)
|
||||||
assertIs<ConnectResult.AlreadyConnected>(result.result)
|
assertIs<ConnectResult.AlreadyConnected>(result.result)
|
||||||
@@ -66,7 +67,7 @@ class ResponseParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun connectParseAlreadyConnectedCaseInsensitive() {
|
fun connectParseAlreadyConnectedCaseInsensitive() {
|
||||||
val response = BunkerResponseError("req-0", "Already Connected")
|
val response = BunkerResponse("req-0", null, "Already Connected")
|
||||||
val result = ConnectResponse.parse(response)
|
val result = ConnectResponse.parse(response)
|
||||||
assertIs<SignerResult.RequestAddressed.Successful<ConnectResult>>(result)
|
assertIs<SignerResult.RequestAddressed.Successful<ConnectResult>>(result)
|
||||||
assertIs<ConnectResult.AlreadyConnected>(result.result)
|
assertIs<ConnectResult.AlreadyConnected>(result.result)
|
||||||
@@ -74,14 +75,14 @@ class ResponseParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun connectParseRealError() {
|
fun connectParseRealError() {
|
||||||
val response = BunkerResponseError("req-0", "unauthorized")
|
val response = BunkerResponse("req-0", null, "unauthorized")
|
||||||
val result = ConnectResponse.parse(response)
|
val result = ConnectResponse.parse(response)
|
||||||
assertIs<SignerResult.RequestAddressed.Rejected<ConnectResult>>(result)
|
assertIs<SignerResult.RequestAddressed.Rejected<ConnectResult>>(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun connectParseUnexpected() {
|
fun connectParseNoResultNoError() {
|
||||||
val response = BunkerResponsePong("req-0")
|
val response = BunkerResponse("req-0", null, null)
|
||||||
val result = ConnectResponse.parse(response)
|
val result = ConnectResponse.parse(response)
|
||||||
assertIs<SignerResult.RequestAddressed.ReceivedButCouldNotPerform<ConnectResult>>(result)
|
assertIs<SignerResult.RequestAddressed.ReceivedButCouldNotPerform<ConnectResult>>(result)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user