Merge pull request #1789 from nrobi144/fix/nip46-quartz-bugs
fix(quartz): fix NIP-44 key mutation and NIP-46 connect response handling
This commit is contained in:
+43
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* 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.nip46RemoteSigner.signer
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponse
|
||||||
|
|
||||||
|
class ConnectResponse {
|
||||||
|
companion object {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-4
@@ -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 = {
|
||||||
@@ -230,11 +230,11 @@ class NostrSignerRemote(
|
|||||||
secret = secret,
|
secret = secret,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
parser = PubKeyResponse::parse,
|
parser = ConnectResponse::parse,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (result is SignerResult.RequestAddressed.Successful<PublicKeyResult>) {
|
if (result is SignerResult.RequestAddressed.Successful<ConnectResult>) {
|
||||||
return result.result.pubkey
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
throw convertExceptions("Could not connect", result)
|
throw convertExceptions("Could not connect", result)
|
||||||
|
|||||||
+6
@@ -67,3 +67,9 @@ data class PingResult(
|
|||||||
data class PublicKeyResult(
|
data class PublicKeyResult(
|
||||||
val pubkey: String,
|
val pubkey: String,
|
||||||
) : IResult
|
) : IResult
|
||||||
|
|
||||||
|
sealed interface ConnectResult : IResult {
|
||||||
|
data object Ack : ConnectResult
|
||||||
|
|
||||||
|
data object AlreadyConnected : ConnectResult
|
||||||
|
}
|
||||||
|
|||||||
+103
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* 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.nip44Encryption
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.toHexKey
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NIP-44v2 tests verifying conversation key derivation, ECDH symmetry,
|
||||||
|
* and encrypt/decrypt round-trips on JVM Desktop.
|
||||||
|
*/
|
||||||
|
class Nip44v2JvmTest {
|
||||||
|
@Test
|
||||||
|
fun conversationKeyFromSpecVector1() {
|
||||||
|
val nip44v2 = Nip44v2()
|
||||||
|
val convKey =
|
||||||
|
nip44v2.getConversationKey(
|
||||||
|
"315e59ff51cb9209768cf7da80791ddcaae56ac9775eb25b6dee1234bc5d2268".hexToByteArray(),
|
||||||
|
"c2f9d9948dc8c7c38321e4b85c8558872eafa0641cd269db76848a6073e69133".hexToByteArray(),
|
||||||
|
)
|
||||||
|
assertEquals(
|
||||||
|
"3dfef0ce2a4d80a25e7a328accf73448ef67096f65f79588e358d9a0eb9013f1",
|
||||||
|
convKey.toHexKey(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun conversationKeyFromSpecVector2() {
|
||||||
|
val nip44v2 = Nip44v2()
|
||||||
|
val convKey =
|
||||||
|
nip44v2.getConversationKey(
|
||||||
|
"a1e37752c9fdc1273be53f68c5f74be7c8905728e8de75800b94262f9497c86e".hexToByteArray(),
|
||||||
|
"03bb7947065dde12ba991ea045132581d0954f042c84e06d8c00066e23c1a800".hexToByteArray(),
|
||||||
|
)
|
||||||
|
assertEquals(
|
||||||
|
"4d14f36e81b8452128da64fe6f1eae873baae2f444b02c950b90e43553f2178b",
|
||||||
|
convKey.toHexKey(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun conversationKeyIsSymmetric() {
|
||||||
|
val nip44v2 = Nip44v2()
|
||||||
|
val privA = "f410f88bcec6cbfda04d6a273c7b1dd8bba144cd45b71e87109cfa11dd7ed561".hexToByteArray()
|
||||||
|
val privB = "65f039136f8da8d3e87b4818746b53318d5481e24b2673f162815144223a0b5a".hexToByteArray()
|
||||||
|
val pubA = KeyPair(privA).pubKey
|
||||||
|
val pubB = KeyPair(privB).pubKey
|
||||||
|
|
||||||
|
val convAB = nip44v2.getConversationKey(privA, pubB)
|
||||||
|
val convBA = nip44v2.getConversationKey(privB, pubA)
|
||||||
|
|
||||||
|
assertEquals(convAB.toHexKey(), convBA.toHexKey())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun encryptDecryptRoundTrip() {
|
||||||
|
val nip44v2 = Nip44v2()
|
||||||
|
val privA = "0000000000000000000000000000000000000000000000000000000000000001".hexToByteArray()
|
||||||
|
val privB = "0000000000000000000000000000000000000000000000000000000000000002".hexToByteArray()
|
||||||
|
val pubA = KeyPair(privA).pubKey
|
||||||
|
val pubB = KeyPair(privB).pubKey
|
||||||
|
|
||||||
|
val encrypted = nip44v2.encrypt("hello world", privA, pubB)
|
||||||
|
val decrypted = nip44v2.decrypt(encrypted, privB, pubA)
|
||||||
|
assertEquals("hello world", decrypted)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun crossKeyPairDecrypt() {
|
||||||
|
val nip44v2 = Nip44v2()
|
||||||
|
val ephemeralPriv = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".hexToByteArray()
|
||||||
|
val signerPriv = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb".hexToByteArray()
|
||||||
|
val ephemeralPub = KeyPair(ephemeralPriv).pubKey
|
||||||
|
val signerPub = KeyPair(signerPriv).pubKey
|
||||||
|
|
||||||
|
val request = """{"id":"test","method":"connect","params":["deadbeef"]}"""
|
||||||
|
val encryptedRequest = nip44v2.encrypt(request, ephemeralPriv, signerPub)
|
||||||
|
|
||||||
|
val decryptedRequest = nip44v2.decrypt(encryptedRequest, signerPriv, ephemeralPub)
|
||||||
|
assertEquals(request, decryptedRequest)
|
||||||
|
}
|
||||||
|
}
|
||||||
+284
@@ -0,0 +1,284 @@
|
|||||||
|
/*
|
||||||
|
* 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.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
|
||||||
|
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponseError
|
||||||
|
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponseEvent
|
||||||
|
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponsePong
|
||||||
|
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponsePublicKey
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertIs
|
||||||
|
|
||||||
|
class ResponseParserTest {
|
||||||
|
// --- ConnectResponse ---
|
||||||
|
// 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 = 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun connectParseAlreadyConnected() {
|
||||||
|
val response = BunkerResponse("req-0", null, "already connected")
|
||||||
|
val result = ConnectResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.Successful<ConnectResult>>(result)
|
||||||
|
assertIs<ConnectResult.AlreadyConnected>(result.result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun connectParseAlreadyConnectedCaseInsensitive() {
|
||||||
|
val response = BunkerResponse("req-0", null, "Already Connected")
|
||||||
|
val result = ConnectResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.Successful<ConnectResult>>(result)
|
||||||
|
assertIs<ConnectResult.AlreadyConnected>(result.result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun connectParseRealError() {
|
||||||
|
val response = BunkerResponse("req-0", null, "unauthorized")
|
||||||
|
val result = ConnectResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.Rejected<ConnectResult>>(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun connectParseNoResultNoError() {
|
||||||
|
val response = BunkerResponse("req-0", null, null)
|
||||||
|
val result = ConnectResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.ReceivedButCouldNotPerform<ConnectResult>>(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- PingResponse ---
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun pingParsePong() {
|
||||||
|
val response = BunkerResponsePong("req-1")
|
||||||
|
val result = PingResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.Successful<PingResult>>(result)
|
||||||
|
assertEquals("req-1", result.result.pong)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun pingParseError() {
|
||||||
|
val response = BunkerResponseError("req-1", "not allowed")
|
||||||
|
val result = PingResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.Rejected<PingResult>>(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun pingParseUnexpected() {
|
||||||
|
val response = BunkerResponseAck("req-1")
|
||||||
|
val result = PingResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.ReceivedButCouldNotPerform<PingResult>>(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- PubKeyResponse ---
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun pubKeyParseSuccess() {
|
||||||
|
val hex = "a".repeat(64)
|
||||||
|
val response = BunkerResponsePublicKey("req-2", hex)
|
||||||
|
val result = PubKeyResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.Successful<PublicKeyResult>>(result)
|
||||||
|
assertEquals(hex, result.result.pubkey)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun pubKeyParseError() {
|
||||||
|
val response = BunkerResponseError("req-2", "denied")
|
||||||
|
val result = PubKeyResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.Rejected<PublicKeyResult>>(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun pubKeyParseUnexpected() {
|
||||||
|
val response = BunkerResponseAck("req-2")
|
||||||
|
val result = PubKeyResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.ReceivedButCouldNotPerform<PublicKeyResult>>(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- SignResponse ---
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun signParseValidEvent() =
|
||||||
|
runTest {
|
||||||
|
val signer = NostrSignerInternal(KeyPair())
|
||||||
|
val event: Event =
|
||||||
|
signer.sign(
|
||||||
|
createdAt = 1234L,
|
||||||
|
kind = 1,
|
||||||
|
tags = emptyArray(),
|
||||||
|
content = "hello",
|
||||||
|
)
|
||||||
|
val response = BunkerResponseEvent("req-3", event)
|
||||||
|
val result = SignResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.Successful<SignResult>>(result)
|
||||||
|
assertEquals(event.id, result.result.event.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun signParseInvalidSignature() {
|
||||||
|
val event =
|
||||||
|
Event(
|
||||||
|
id = "a".repeat(64),
|
||||||
|
pubKey = "b".repeat(64),
|
||||||
|
createdAt = 1234L,
|
||||||
|
kind = 1,
|
||||||
|
tags = emptyArray(),
|
||||||
|
content = "hello",
|
||||||
|
sig = "c".repeat(128),
|
||||||
|
)
|
||||||
|
val response = BunkerResponseEvent("req-3", event)
|
||||||
|
val result = SignResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.ReceivedButCouldNotVerifyResultingEvent<SignResult>>(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun signParseError() {
|
||||||
|
val response = BunkerResponseError("req-3", "denied")
|
||||||
|
val result = SignResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.Rejected<SignResult>>(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun signParseUnexpected() {
|
||||||
|
val response = BunkerResponseAck("req-3")
|
||||||
|
val result = SignResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.ReceivedButCouldNotPerform<SignResult>>(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Nip04EncryptResponse ---
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun nip04EncryptParseSuccess() {
|
||||||
|
val response = BunkerResponseEncrypt("req-4", "ciphertext-data")
|
||||||
|
val result = Nip04EncryptResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.Successful<EncryptionResult>>(result)
|
||||||
|
assertEquals("ciphertext-data", result.result.ciphertext)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun nip04EncryptParseError() {
|
||||||
|
val response = BunkerResponseError("req-4", "fail")
|
||||||
|
val result = Nip04EncryptResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.Rejected<EncryptionResult>>(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun nip04EncryptParseUnexpected() {
|
||||||
|
val response = BunkerResponsePong("req-4")
|
||||||
|
val result = Nip04EncryptResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.ReceivedButCouldNotPerform<EncryptionResult>>(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Nip04DecryptResponse ---
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun nip04DecryptParseSuccess() {
|
||||||
|
val response = BunkerResponseDecrypt("req-5", "plain-text")
|
||||||
|
val result = Nip04DecryptResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.Successful<DecryptionResult>>(result)
|
||||||
|
assertEquals("plain-text", result.result.plaintext)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun nip04DecryptParseError() {
|
||||||
|
val response = BunkerResponseError("req-5", "fail")
|
||||||
|
val result = Nip04DecryptResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.Rejected<DecryptionResult>>(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun nip04DecryptParseUnexpected() {
|
||||||
|
val response = BunkerResponsePong("req-5")
|
||||||
|
val result = Nip04DecryptResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.ReceivedButCouldNotPerform<DecryptionResult>>(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Nip44EncryptResponse ---
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun nip44EncryptParseSuccess() {
|
||||||
|
val response = BunkerResponseEncrypt("req-6", "nip44-cipher")
|
||||||
|
val result = Nip44EncryptResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.Successful<EncryptionResult>>(result)
|
||||||
|
assertEquals("nip44-cipher", result.result.ciphertext)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun nip44EncryptParseError() {
|
||||||
|
val response = BunkerResponseError("req-6", "fail")
|
||||||
|
val result = Nip44EncryptResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.Rejected<EncryptionResult>>(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun nip44EncryptParseUnexpected() {
|
||||||
|
val response = BunkerResponseAck("req-6")
|
||||||
|
val result = Nip44EncryptResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.ReceivedButCouldNotPerform<EncryptionResult>>(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Nip44DecryptResponse ---
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun nip44DecryptParseSuccess() {
|
||||||
|
val response = BunkerResponseDecrypt("req-7", "nip44-plain")
|
||||||
|
val result = Nip44DecryptResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.Successful<DecryptionResult>>(result)
|
||||||
|
assertEquals("nip44-plain", result.result.plaintext)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun nip44DecryptParseError() {
|
||||||
|
val response = BunkerResponseError("req-7", "fail")
|
||||||
|
val result = Nip44DecryptResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.Rejected<DecryptionResult>>(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun nip44DecryptParseUnexpected() {
|
||||||
|
val response = BunkerResponseAck("req-7")
|
||||||
|
val result = Nip44DecryptResponse.parse(response)
|
||||||
|
assertIs<SignerResult.RequestAddressed.ReceivedButCouldNotPerform<DecryptionResult>>(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,7 +31,7 @@ class FixedKey(
|
|||||||
) : SecretKey {
|
) : SecretKey {
|
||||||
override fun getAlgorithm() = algo
|
override fun getAlgorithm() = algo
|
||||||
|
|
||||||
override fun getEncoded() = key
|
override fun getEncoded() = key.copyOf()
|
||||||
|
|
||||||
override fun getFormat() = "RAW"
|
override fun getFormat() = "RAW"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user