diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/jackson/JsonMapper.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/jackson/JsonMapper.kt index b365d765d..3a24f550f 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/jackson/JsonMapper.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/jackson/JsonMapper.kt @@ -35,6 +35,9 @@ import com.vitorpamplona.quartz.nip47WalletConnect.Request import com.vitorpamplona.quartz.nip47WalletConnect.RequestDeserializer import com.vitorpamplona.quartz.nip47WalletConnect.Response import com.vitorpamplona.quartz.nip47WalletConnect.ResponseDeserializer +import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResult +import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResultJsonDeserializer +import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResultJsonSerializer import com.vitorpamplona.quartz.nip55AndroidSigner.api.permission.Permission import com.vitorpamplona.quartz.nip55AndroidSigner.api.permission.PermissionDeserializer import com.vitorpamplona.quartz.nip55AndroidSigner.api.permission.PermissionSerializer @@ -65,7 +68,9 @@ class JsonMapper { .addSerializer(BunkerResponse::class.java, BunkerResponse.BunkerResponseSerializer()) .addDeserializer(BunkerResponse::class.java, BunkerResponse.BunkerResponseDeserializer()) .addDeserializer(Permission::class.java, PermissionDeserializer()) - .addSerializer(Permission::class.java, PermissionSerializer()), + .addSerializer(Permission::class.java, PermissionSerializer()) + .addDeserializer(IntentResult::class.java, IntentResultJsonDeserializer()) + .addSerializer(IntentResult::class.java, IntentResultJsonSerializer()), ) fun fromJson(json: String): Event = mapper.readValue(json, Event::class.java) diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/IntentRequestManager.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/IntentRequestManager.kt index d10768450..8fc522961 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/IntentRequestManager.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/IntentRequestManager.kt @@ -23,13 +23,13 @@ package com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground import android.content.ActivityNotFoundException import android.content.Intent import android.util.Log -import android.util.Log.e import androidx.collection.LruCache import com.vitorpamplona.quartz.nip55AndroidSigner.api.IResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult +import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResult import com.vitorpamplona.quartz.utils.RandomInstance import com.vitorpamplona.quartz.utils.tryAndWait -import kotlinx.coroutines.CancellationException +import kotlin.collections.forEach import kotlin.coroutines.Continuation import kotlin.coroutines.resume @@ -61,7 +61,7 @@ class IntentRequestManager( val activityNotFoundIntent = Intent() // LRU cache to store pending requests and their continuations. - private val awaitingRequests = LruCache>(2000) + private val awaitingRequests = LruCache>(2000) // Function to launch an Intent in the foreground. private var appLauncher: ((Intent) -> Unit)? = null @@ -79,10 +79,21 @@ class IntentRequestManager( } fun newResponse(data: Intent) { - val callId = data.getStringExtra("id") - if (callId != null) { - awaitingRequests[callId]?.resume(data) - awaitingRequests.remove(callId) + val results = data.getStringExtra("results") + if (results != null) { + // This happens when the intent responds to many requests at the same time. + IntentResult.fromJsonArray(results).forEach { result -> + if (result.id != null) { + awaitingRequests[result.id]?.resume(result) + awaitingRequests.remove(result.id) + } + } + } else { + val result = IntentResult.fromIntent(data) + if (result.id != null) { + awaitingRequests[result.id]?.resume(result) + awaitingRequests.remove(result.id) + } } } @@ -102,7 +113,7 @@ class IntentRequestManager( */ suspend fun launchWaitAndParse( requestIntentBuilder: () -> Intent, - parser: (intent: Intent) -> SignerResult.RequestAddressed, + parser: (intent: IntentResult) -> SignerResult.RequestAddressed, ): SignerResult.RequestAddressed = appLauncher?.let { launcher -> val requestIntent = requestIntentBuilder() @@ -111,32 +122,31 @@ class IntentRequestManager( requestIntent.putExtra("id", callId) requestIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP) - val resultIntent = - tryAndWait(foregroundApprovalTimeout) { continuation -> - continuation.invokeOnCancellation { - awaitingRequests.remove(callId) + try { + val resultIntent = + tryAndWait(foregroundApprovalTimeout) { continuation -> + continuation.invokeOnCancellation { + awaitingRequests.remove(callId) + } + + awaitingRequests.put(callId, continuation) + + try { + launcher.invoke(requestIntent) + } catch (e: Exception) { + Log.e("ExternalSigner", "Error launching intent", e) + awaitingRequests.remove(callId) + throw e + } } - awaitingRequests.put(callId, continuation) - - try { - launcher.invoke(requestIntent) - } catch (e: ActivityNotFoundException) { - Log.e("ExternalSigner", "Error launching intent", e) - awaitingRequests.remove(callId) - continuation.resume(activityNotFoundIntent) - } catch (e: Exception) { - Log.e("ExternalSigner", "Error launching intent", e) - awaitingRequests.remove(callId) - continuation.resume(null) - if (e is CancellationException) throw e - } + when (resultIntent) { + null -> SignerResult.RequestAddressed.TimedOut() + else -> parser(resultIntent) } - - when (resultIntent) { - null -> SignerResult.RequestAddressed.TimedOut() - activityNotFoundIntent -> SignerResult.RequestAddressed.SignerNotFound() - else -> parser(resultIntent) + } catch (e: ActivityNotFoundException) { + Log.e("ExternalSigner", "Error launching intent: Signer not found", e) + SignerResult.RequestAddressed.SignerNotFound() } } ?: SignerResult.RequestAddressed.NoActivityToLaunchFrom() } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/DecryptZapResponse.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/DecryptZapResponse.kt index 0d602809b..baac54777 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/DecryptZapResponse.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/DecryptZapResponse.kt @@ -24,6 +24,7 @@ import android.content.Intent import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.ZapEventDecryptionResult +import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResult import com.vitorpamplona.quartz.nip57Zaps.LnZapPrivateEvent class DecryptZapResponse { @@ -34,8 +35,8 @@ class DecryptZapResponse { return intent } - fun parse(intent: Intent): SignerResult.RequestAddressed { - val eventJson = intent.getStringExtra("result") + fun parse(intent: IntentResult): SignerResult.RequestAddressed { + val eventJson = intent.result return if (!eventJson.isNullOrBlank()) { if (eventJson.startsWith("{")) { val event = Event.fromJsonOrNull(eventJson) as? LnZapPrivateEvent diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/DeriveKeyResponse.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/DeriveKeyResponse.kt index 8a4a3085c..6369b596e 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/DeriveKeyResponse.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/DeriveKeyResponse.kt @@ -20,14 +20,14 @@ */ package com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.responses -import android.content.Intent import com.vitorpamplona.quartz.nip55AndroidSigner.api.DerivationResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult +import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResult class DeriveKeyResponse { companion object { - fun parse(intent: Intent): SignerResult.RequestAddressed { - val newPrivateKey = intent.getStringExtra("result") + fun parse(intent: IntentResult): SignerResult.RequestAddressed { + val newPrivateKey = intent.result return if (newPrivateKey != null) { SignerResult.RequestAddressed.Successful(DerivationResult(newPrivateKey)) } else { diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/LoginResponse.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/LoginResponse.kt index 1a5cca556..5594a5156 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/LoginResponse.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/LoginResponse.kt @@ -20,15 +20,15 @@ */ package com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.responses -import android.content.Intent import com.vitorpamplona.quartz.nip55AndroidSigner.api.PubKeyResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult +import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResult class LoginResponse { companion object { - fun parse(intent: Intent): SignerResult.RequestAddressed { - val pubkey = intent.getStringExtra("result") - val packageName = intent.getStringExtra("package") + fun parse(intent: IntentResult): SignerResult.RequestAddressed { + val pubkey = intent.result + val packageName = intent.`package` return if (pubkey != null && packageName != null) { SignerResult.RequestAddressed.Successful( diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/Nip04DecryptResponse.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/Nip04DecryptResponse.kt index c7e78b366..2b9d0cc4c 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/Nip04DecryptResponse.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/Nip04DecryptResponse.kt @@ -20,14 +20,14 @@ */ package com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.responses -import android.content.Intent import com.vitorpamplona.quartz.nip55AndroidSigner.api.DecryptionResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult +import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResult class Nip04DecryptResponse { companion object { - fun parse(intent: Intent): SignerResult.RequestAddressed { - val ciphertext = intent.getStringExtra("result") + fun parse(intent: IntentResult): SignerResult.RequestAddressed { + val ciphertext = intent.result return if (ciphertext != null) { SignerResult.RequestAddressed.Successful(DecryptionResult(ciphertext)) } else { diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/Nip04EncryptResponse.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/Nip04EncryptResponse.kt index d16ea4d7b..35b58ff64 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/Nip04EncryptResponse.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/Nip04EncryptResponse.kt @@ -20,14 +20,14 @@ */ package com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.responses -import android.content.Intent import com.vitorpamplona.quartz.nip55AndroidSigner.api.EncryptionResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult +import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResult class Nip04EncryptResponse { companion object { - fun parse(intent: Intent): SignerResult.RequestAddressed { - val ciphertext = intent.getStringExtra("result") + fun parse(intent: IntentResult): SignerResult.RequestAddressed { + val ciphertext = intent.result return if (ciphertext != null) { SignerResult.RequestAddressed.Successful(EncryptionResult(ciphertext)) } else { diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/Nip44DecryptResponse.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/Nip44DecryptResponse.kt index f320afb79..fc3a78b89 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/Nip44DecryptResponse.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/Nip44DecryptResponse.kt @@ -20,14 +20,14 @@ */ package com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.responses -import android.content.Intent import com.vitorpamplona.quartz.nip55AndroidSigner.api.DecryptionResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult +import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResult class Nip44DecryptResponse { companion object { - fun parse(intent: Intent): SignerResult.RequestAddressed { - val ciphertext = intent.getStringExtra("result") + fun parse(intent: IntentResult): SignerResult.RequestAddressed { + val ciphertext = intent.result return if (ciphertext != null) { SignerResult.RequestAddressed.Successful(DecryptionResult(ciphertext)) } else { diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/Nip44EncryptResponse.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/Nip44EncryptResponse.kt index c9a9412bd..b8cd34466 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/Nip44EncryptResponse.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/Nip44EncryptResponse.kt @@ -20,14 +20,14 @@ */ package com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.responses -import android.content.Intent import com.vitorpamplona.quartz.nip55AndroidSigner.api.EncryptionResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult +import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResult class Nip44EncryptResponse { companion object { - fun parse(intent: Intent): SignerResult.RequestAddressed { - val ciphertext = intent.getStringExtra("result") + fun parse(intent: IntentResult): SignerResult.RequestAddressed { + val ciphertext = intent.result return if (ciphertext != null) { SignerResult.RequestAddressed.Successful(EncryptionResult(ciphertext)) } else { diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/SignResponse.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/SignResponse.kt index 25d040ca4..e6cc27b8f 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/SignResponse.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/responses/SignResponse.kt @@ -20,20 +20,20 @@ */ package com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.responses -import android.content.Intent import com.vitorpamplona.quartz.EventFactory import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.verify import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult +import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResult class SignResponse { companion object { fun parse( - intent: Intent, + intent: IntentResult, unsignedEvent: Event, ): SignerResult.RequestAddressed { - val eventJson = intent.getStringExtra("event") + val eventJson = intent.event return if (eventJson != null) { if (eventJson.startsWith("{")) { val event = Event.fromJsonOrNull(eventJson) @@ -50,7 +50,7 @@ class SignResponse { SignerResult.RequestAddressed.ReceivedButCouldNotPerform(eventJson) } } else { - val signature = intent.getStringExtra("result") + val signature = intent.result if (signature != null && signature.length == 128) { val event: Event = EventFactory.create( diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/results/IntentResult.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/results/IntentResult.kt new file mode 100644 index 000000000..7bd374ac3 --- /dev/null +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/results/IntentResult.kt @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results + +import android.content.Intent +import com.fasterxml.jackson.module.kotlin.readValue +import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper + +class IntentResult( + val `package`: String?, + val result: String?, + val event: String?, + val id: String?, +) { + fun toJson(): String = JsonMapper.mapper.writeValueAsString(this) + + fun toIntent(): Intent { + val intent = Intent() + intent.putExtra("id", id) + intent.putExtra("result", result) + intent.putExtra("event", event) + intent.putExtra("package", `package`) + return intent + } + + companion object { + fun fromIntent(data: Intent): IntentResult = + IntentResult( + id = data.getStringExtra("id"), + result = data.getStringExtra("result"), + event = data.getStringExtra("event"), + `package` = data.getStringExtra("package"), + ) + + fun fromJson(json: String): IntentResult = JsonMapper.mapper.readValue(json) + + fun fromJsonArray(json: String): List = JsonMapper.mapper.readValue>(json) + } +} diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/results/IntentResultJsonDeserializer.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/results/IntentResultJsonDeserializer.kt new file mode 100644 index 000000000..e53cb8be2 --- /dev/null +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/results/IntentResultJsonDeserializer.kt @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results + +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.deser.std.StdDeserializer + +class IntentResultJsonDeserializer : StdDeserializer(IntentResult::class.java) { + override fun deserialize( + jp: JsonParser, + ctxt: DeserializationContext, + ): IntentResult { + val jsonObject: JsonNode = jp.codec.readTree(jp) + return IntentResult( + `package` = jsonObject.get("package")?.asText()?.intern(), + result = jsonObject.get("result")?.asText()?.intern(), + event = jsonObject.get("event")?.asText()?.intern(), + id = jsonObject.get("id")?.asText()?.intern(), + ) + } +} diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/results/IntentResultJsonSerializer.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/results/IntentResultJsonSerializer.kt new file mode 100644 index 000000000..289f4daed --- /dev/null +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/api/foreground/intents/results/IntentResultJsonSerializer.kt @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results + +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.ser.std.StdSerializer + +class IntentResultJsonSerializer : StdSerializer(IntentResult::class.java) { + override fun serialize( + result: IntentResult, + gen: JsonGenerator, + provider: SerializerProvider, + ) { + gen.writeStartObject() + result.`package`?.let { gen.writeStringField("package", it) } + result.result?.let { gen.writeStringField("result", it) } + result.event?.let { gen.writeStringField("event", it) } + result.id?.let { gen.writeStringField("id", it) } + gen.writeEndObject() + } +} diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/client/ExternalSignerLogin.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/client/ExternalSignerLogin.kt index b5e3fb092..015c3fc65 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/client/ExternalSignerLogin.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip55AndroidSigner/client/ExternalSignerLogin.kt @@ -25,6 +25,7 @@ import com.vitorpamplona.quartz.nip55AndroidSigner.api.PubKeyResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.requests.LoginRequest import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.responses.LoginResponse +import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.permission.Permission object ExternalSignerLogin { @@ -34,5 +35,8 @@ object ExternalSignerLogin { return intent } - fun parseResult(data: Intent): SignerResult = LoginResponse.parse(data) + fun parseResult(data: Intent): SignerResult { + val result = IntentResult.fromIntent(data) + return LoginResponse.parse(result) + } }