Fixes NIP-55 return as a list of results on the intent.

This commit is contained in:
Vitor Pamplona
2025-07-22 10:34:42 -04:00
parent 8fe13717dd
commit e6b5d51cda
14 changed files with 216 additions and 58 deletions

View File

@@ -35,6 +35,9 @@ import com.vitorpamplona.quartz.nip47WalletConnect.Request
import com.vitorpamplona.quartz.nip47WalletConnect.RequestDeserializer import com.vitorpamplona.quartz.nip47WalletConnect.RequestDeserializer
import com.vitorpamplona.quartz.nip47WalletConnect.Response import com.vitorpamplona.quartz.nip47WalletConnect.Response
import com.vitorpamplona.quartz.nip47WalletConnect.ResponseDeserializer 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.Permission
import com.vitorpamplona.quartz.nip55AndroidSigner.api.permission.PermissionDeserializer import com.vitorpamplona.quartz.nip55AndroidSigner.api.permission.PermissionDeserializer
import com.vitorpamplona.quartz.nip55AndroidSigner.api.permission.PermissionSerializer import com.vitorpamplona.quartz.nip55AndroidSigner.api.permission.PermissionSerializer
@@ -65,7 +68,9 @@ class JsonMapper {
.addSerializer(BunkerResponse::class.java, BunkerResponse.BunkerResponseSerializer()) .addSerializer(BunkerResponse::class.java, BunkerResponse.BunkerResponseSerializer())
.addDeserializer(BunkerResponse::class.java, BunkerResponse.BunkerResponseDeserializer()) .addDeserializer(BunkerResponse::class.java, BunkerResponse.BunkerResponseDeserializer())
.addDeserializer(Permission::class.java, PermissionDeserializer()) .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) fun fromJson(json: String): Event = mapper.readValue(json, Event::class.java)

View File

@@ -23,13 +23,13 @@ package com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
import android.content.Intent import android.content.Intent
import android.util.Log import android.util.Log
import android.util.Log.e
import androidx.collection.LruCache import androidx.collection.LruCache
import com.vitorpamplona.quartz.nip55AndroidSigner.api.IResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.IResult
import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult 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.RandomInstance
import com.vitorpamplona.quartz.utils.tryAndWait import com.vitorpamplona.quartz.utils.tryAndWait
import kotlinx.coroutines.CancellationException import kotlin.collections.forEach
import kotlin.coroutines.Continuation import kotlin.coroutines.Continuation
import kotlin.coroutines.resume import kotlin.coroutines.resume
@@ -61,7 +61,7 @@ class IntentRequestManager(
val activityNotFoundIntent = Intent() val activityNotFoundIntent = Intent()
// LRU cache to store pending requests and their continuations. // LRU cache to store pending requests and their continuations.
private val awaitingRequests = LruCache<String, Continuation<Intent>>(2000) private val awaitingRequests = LruCache<String, Continuation<IntentResult>>(2000)
// Function to launch an Intent in the foreground. // Function to launch an Intent in the foreground.
private var appLauncher: ((Intent) -> Unit)? = null private var appLauncher: ((Intent) -> Unit)? = null
@@ -79,10 +79,21 @@ class IntentRequestManager(
} }
fun newResponse(data: Intent) { fun newResponse(data: Intent) {
val callId = data.getStringExtra("id") val results = data.getStringExtra("results")
if (callId != null) { if (results != null) {
awaitingRequests[callId]?.resume(data) // This happens when the intent responds to many requests at the same time.
awaitingRequests.remove(callId) 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 <T : IResult> launchWaitAndParse( suspend fun <T : IResult> launchWaitAndParse(
requestIntentBuilder: () -> Intent, requestIntentBuilder: () -> Intent,
parser: (intent: Intent) -> SignerResult.RequestAddressed<T>, parser: (intent: IntentResult) -> SignerResult.RequestAddressed<T>,
): SignerResult.RequestAddressed<T> = ): SignerResult.RequestAddressed<T> =
appLauncher?.let { launcher -> appLauncher?.let { launcher ->
val requestIntent = requestIntentBuilder() val requestIntent = requestIntentBuilder()
@@ -111,32 +122,31 @@ class IntentRequestManager(
requestIntent.putExtra("id", callId) requestIntent.putExtra("id", callId)
requestIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP) requestIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
val resultIntent = try {
tryAndWait(foregroundApprovalTimeout) { continuation -> val resultIntent =
continuation.invokeOnCancellation { tryAndWait(foregroundApprovalTimeout) { continuation ->
awaitingRequests.remove(callId) 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) when (resultIntent) {
null -> SignerResult.RequestAddressed.TimedOut()
try { else -> parser(resultIntent)
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
}
} }
} catch (e: ActivityNotFoundException) {
when (resultIntent) { Log.e("ExternalSigner", "Error launching intent: Signer not found", e)
null -> SignerResult.RequestAddressed.TimedOut() SignerResult.RequestAddressed.SignerNotFound()
activityNotFoundIntent -> SignerResult.RequestAddressed.SignerNotFound()
else -> parser(resultIntent)
} }
} ?: SignerResult.RequestAddressed.NoActivityToLaunchFrom() } ?: SignerResult.RequestAddressed.NoActivityToLaunchFrom()
} }

View File

@@ -24,6 +24,7 @@ import android.content.Intent
import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.Event
import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult
import com.vitorpamplona.quartz.nip55AndroidSigner.api.ZapEventDecryptionResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.ZapEventDecryptionResult
import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResult
import com.vitorpamplona.quartz.nip57Zaps.LnZapPrivateEvent import com.vitorpamplona.quartz.nip57Zaps.LnZapPrivateEvent
class DecryptZapResponse { class DecryptZapResponse {
@@ -34,8 +35,8 @@ class DecryptZapResponse {
return intent return intent
} }
fun parse(intent: Intent): SignerResult.RequestAddressed<ZapEventDecryptionResult> { fun parse(intent: IntentResult): SignerResult.RequestAddressed<ZapEventDecryptionResult> {
val eventJson = intent.getStringExtra("result") val eventJson = intent.result
return if (!eventJson.isNullOrBlank()) { return if (!eventJson.isNullOrBlank()) {
if (eventJson.startsWith("{")) { if (eventJson.startsWith("{")) {
val event = Event.fromJsonOrNull(eventJson) as? LnZapPrivateEvent val event = Event.fromJsonOrNull(eventJson) as? LnZapPrivateEvent

View File

@@ -20,14 +20,14 @@
*/ */
package com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.responses 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.DerivationResult
import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult
import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResult
class DeriveKeyResponse { class DeriveKeyResponse {
companion object { companion object {
fun parse(intent: Intent): SignerResult.RequestAddressed<DerivationResult> { fun parse(intent: IntentResult): SignerResult.RequestAddressed<DerivationResult> {
val newPrivateKey = intent.getStringExtra("result") val newPrivateKey = intent.result
return if (newPrivateKey != null) { return if (newPrivateKey != null) {
SignerResult.RequestAddressed.Successful(DerivationResult(newPrivateKey)) SignerResult.RequestAddressed.Successful(DerivationResult(newPrivateKey))
} else { } else {

View File

@@ -20,15 +20,15 @@
*/ */
package com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.responses 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.PubKeyResult
import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult
import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResult
class LoginResponse { class LoginResponse {
companion object { companion object {
fun parse(intent: Intent): SignerResult.RequestAddressed<PubKeyResult> { fun parse(intent: IntentResult): SignerResult.RequestAddressed<PubKeyResult> {
val pubkey = intent.getStringExtra("result") val pubkey = intent.result
val packageName = intent.getStringExtra("package") val packageName = intent.`package`
return if (pubkey != null && packageName != null) { return if (pubkey != null && packageName != null) {
SignerResult.RequestAddressed.Successful( SignerResult.RequestAddressed.Successful(

View File

@@ -20,14 +20,14 @@
*/ */
package com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.responses 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.DecryptionResult
import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult
import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResult
class Nip04DecryptResponse { class Nip04DecryptResponse {
companion object { companion object {
fun parse(intent: Intent): SignerResult.RequestAddressed<DecryptionResult> { fun parse(intent: IntentResult): SignerResult.RequestAddressed<DecryptionResult> {
val ciphertext = intent.getStringExtra("result") val ciphertext = intent.result
return if (ciphertext != null) { return if (ciphertext != null) {
SignerResult.RequestAddressed.Successful(DecryptionResult(ciphertext)) SignerResult.RequestAddressed.Successful(DecryptionResult(ciphertext))
} else { } else {

View File

@@ -20,14 +20,14 @@
*/ */
package com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.responses 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.EncryptionResult
import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult
import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResult
class Nip04EncryptResponse { class Nip04EncryptResponse {
companion object { companion object {
fun parse(intent: Intent): SignerResult.RequestAddressed<EncryptionResult> { fun parse(intent: IntentResult): SignerResult.RequestAddressed<EncryptionResult> {
val ciphertext = intent.getStringExtra("result") val ciphertext = intent.result
return if (ciphertext != null) { return if (ciphertext != null) {
SignerResult.RequestAddressed.Successful(EncryptionResult(ciphertext)) SignerResult.RequestAddressed.Successful(EncryptionResult(ciphertext))
} else { } else {

View File

@@ -20,14 +20,14 @@
*/ */
package com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.responses 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.DecryptionResult
import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult
import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResult
class Nip44DecryptResponse { class Nip44DecryptResponse {
companion object { companion object {
fun parse(intent: Intent): SignerResult.RequestAddressed<DecryptionResult> { fun parse(intent: IntentResult): SignerResult.RequestAddressed<DecryptionResult> {
val ciphertext = intent.getStringExtra("result") val ciphertext = intent.result
return if (ciphertext != null) { return if (ciphertext != null) {
SignerResult.RequestAddressed.Successful(DecryptionResult(ciphertext)) SignerResult.RequestAddressed.Successful(DecryptionResult(ciphertext))
} else { } else {

View File

@@ -20,14 +20,14 @@
*/ */
package com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.responses 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.EncryptionResult
import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult
import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResult
class Nip44EncryptResponse { class Nip44EncryptResponse {
companion object { companion object {
fun parse(intent: Intent): SignerResult.RequestAddressed<EncryptionResult> { fun parse(intent: IntentResult): SignerResult.RequestAddressed<EncryptionResult> {
val ciphertext = intent.getStringExtra("result") val ciphertext = intent.result
return if (ciphertext != null) { return if (ciphertext != null) {
SignerResult.RequestAddressed.Successful(EncryptionResult(ciphertext)) SignerResult.RequestAddressed.Successful(EncryptionResult(ciphertext))
} else { } else {

View File

@@ -20,20 +20,20 @@
*/ */
package com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.responses package com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.responses
import android.content.Intent
import com.vitorpamplona.quartz.EventFactory import com.vitorpamplona.quartz.EventFactory
import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.Event
import com.vitorpamplona.quartz.nip01Core.verify import com.vitorpamplona.quartz.nip01Core.verify
import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignResult
import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult
import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.results.IntentResult
class SignResponse { class SignResponse {
companion object { companion object {
fun parse( fun parse(
intent: Intent, intent: IntentResult,
unsignedEvent: Event, unsignedEvent: Event,
): SignerResult.RequestAddressed<SignResult> { ): SignerResult.RequestAddressed<SignResult> {
val eventJson = intent.getStringExtra("event") val eventJson = intent.event
return if (eventJson != null) { return if (eventJson != null) {
if (eventJson.startsWith("{")) { if (eventJson.startsWith("{")) {
val event = Event.fromJsonOrNull(eventJson) val event = Event.fromJsonOrNull(eventJson)
@@ -50,7 +50,7 @@ class SignResponse {
SignerResult.RequestAddressed.ReceivedButCouldNotPerform(eventJson) SignerResult.RequestAddressed.ReceivedButCouldNotPerform(eventJson)
} }
} else { } else {
val signature = intent.getStringExtra("result") val signature = intent.result
if (signature != null && signature.length == 128) { if (signature != null && signature.length == 128) {
val event: Event = val event: Event =
EventFactory.create( EventFactory.create(

View File

@@ -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<IntentResult>(json)
fun fromJsonArray(json: String): List<IntentResult> = JsonMapper.mapper.readValue<List<IntentResult>>(json)
}
}

View File

@@ -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>(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(),
)
}
}

View File

@@ -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>(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()
}
}

View File

@@ -25,6 +25,7 @@ import com.vitorpamplona.quartz.nip55AndroidSigner.api.PubKeyResult
import com.vitorpamplona.quartz.nip55AndroidSigner.api.SignerResult 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.requests.LoginRequest
import com.vitorpamplona.quartz.nip55AndroidSigner.api.foreground.intents.responses.LoginResponse 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 import com.vitorpamplona.quartz.nip55AndroidSigner.api.permission.Permission
object ExternalSignerLogin { object ExternalSignerLogin {
@@ -34,5 +35,8 @@ object ExternalSignerLogin {
return intent return intent
} }
fun parseResult(data: Intent): SignerResult<PubKeyResult> = LoginResponse.parse(data) fun parseResult(data: Intent): SignerResult<PubKeyResult> {
val result = IntentResult.fromIntent(data)
return LoginResponse.parse(result)
}
} }