Merge pull request #505 from greenart7c3/claude/import-statements-cleanup-rhzg13

Clean up imports and remove ExperimentalEncodingApi opt-in
This commit is contained in:
greenart7c3
2026-07-15 16:26:04 -03:00
committed by GitHub
10 changed files with 34 additions and 25 deletions
@@ -22,6 +22,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponse
import com.vitorpamplona.quartz.nip57Zaps.LnZapRequestEvent
import com.vitorpamplona.quartz.utils.TimeUtils
import kotlin.io.encoding.Base64
object AmberUtils {
/**
@@ -31,7 +32,6 @@ object AmberUtils {
* plaintext for logs/display comes from the EncryptedDataKind instead (see
* [nip44v3Plaintext]). [nip44v3Kind]/[nip44v3Scope] are required for V3.
*/
@OptIn(kotlin.io.encoding.ExperimentalEncodingApi::class)
suspend fun encryptOrDecryptData(
data: String,
type: SignerType,
@@ -54,11 +54,11 @@ object AmberUtils {
}
SignerType.NIP44_V3_ENCRYPT -> {
requireNotNull(nip44v3Kind) { "kind is required for NIP44_V3_ENCRYPT" }
account.nip44v3Encrypt(kotlin.io.encoding.Base64.decode(data), pubKey, nip44v3Kind, nip44v3Scope)
account.nip44v3Encrypt(Base64.decode(data), pubKey, nip44v3Kind, nip44v3Scope)
}
SignerType.NIP44_V3_DECRYPT -> {
requireNotNull(nip44v3Kind) { "kind is required for NIP44_V3_DECRYPT" }
kotlin.io.encoding.Base64.encode(account.nip44v3Decrypt(data, pubKey, nip44v3Kind, nip44v3Scope))
Base64.encode(account.nip44v3Decrypt(data, pubKey, nip44v3Kind, nip44v3Scope))
}
else -> {
account.nip44Decrypt(data, pubKey)
@@ -13,6 +13,7 @@ import com.greenart7c3.nostrsigner.database.LogEntity
import com.greenart7c3.nostrsigner.database.generateBunkerPrivKey
import com.greenart7c3.nostrsigner.models.Account
import com.greenart7c3.nostrsigner.models.AmberBunkerRequest
import com.greenart7c3.nostrsigner.models.EncryptedDataKind
import com.greenart7c3.nostrsigner.models.EncryptionType
import com.greenart7c3.nostrsigner.models.Permission
import com.greenart7c3.nostrsigner.models.SignerType
@@ -290,7 +291,7 @@ object BunkerRequestUtils {
oldKey: String = "",
deleteAfter: Long = 0L,
relay: String = "",
encryptedData: com.greenart7c3.nostrsigner.models.EncryptedDataKind? = null,
encryptedData: EncryptedDataKind? = null,
decryptTypeScope: DecryptTypeScope = DecryptTypeScope.ALL,
) {
onLoading(true)
@@ -68,6 +68,8 @@ import com.vitorpamplona.quartz.nip46RemoteSigner.NostrConnectEvent
import com.vitorpamplona.quartz.nip59Giftwrap.seals.SealedRumorEvent
import com.vitorpamplona.quartz.utils.TimeUtils
import java.util.UUID
import kotlin.io.encoding.Base64
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.launch
class EventNotificationConsumer(private val applicationContext: Context) {
@@ -844,7 +846,6 @@ class EventNotificationConsumer(private val applicationContext: Context) {
* history/display can use the readable plaintext. Returns null if it can't
* be produced (the request is auto-rejected elsewhere in that case).
*/
@OptIn(kotlin.io.encoding.ExperimentalEncodingApi::class)
private fun nip44v3EncryptedDataKind(
bunkerRequest: BunkerRequest,
acc: Account,
@@ -856,15 +857,15 @@ class EventNotificationConsumer(private val applicationContext: Context) {
return try {
// text = readable plaintext (for display/history); result = wire value.
if (bunkerRequest.method == "nip44v3_encrypt") {
val plainBytes = kotlin.io.encoding.Base64.decode(data)
val plainBytes = Base64.decode(data)
val ciphertext = acc.nip44v3Encrypt(plainBytes, pubKey, kind, scope)
ClearTextEncryptedDataKind(plainBytes.toString(Charsets.UTF_8), ciphertext)
} else {
val plainBytes = acc.nip44v3Decrypt(data, pubKey, kind, scope)
ClearTextEncryptedDataKind(plainBytes.toString(Charsets.UTF_8), kotlin.io.encoding.Base64.encode(plainBytes))
ClearTextEncryptedDataKind(plainBytes.toString(Charsets.UTF_8), Base64.encode(plainBytes))
}
} catch (e: Exception) {
if (e is kotlinx.coroutines.CancellationException) throw e
if (e is CancellationException) throw e
null
}
}
@@ -889,7 +890,7 @@ class EventNotificationConsumer(private val applicationContext: Context) {
acc.nip44v3Decrypt(data, pubKey, kind, scope)
null
} catch (e: Exception) {
if (e is kotlinx.coroutines.CancellationException) throw e
if (e is CancellationException) throw e
// Keep the response generic so we don't leak the ciphertext's
// embedded context back to the requester.
"could not decrypt the message"
@@ -49,9 +49,9 @@ import com.vitorpamplona.quartz.utils.Hex
import com.vitorpamplona.quartz.utils.TimeUtils
import java.io.ByteArrayOutputStream
import java.net.URLDecoder
import java.util.Base64
import java.util.UUID
import java.util.zip.GZIPOutputStream
import kotlin.io.encoding.Base64
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList
@@ -584,7 +584,6 @@ object IntentUtils {
}
}
@OptIn(kotlin.io.encoding.ExperimentalEncodingApi::class)
private suspend fun getEncryptedDataKind(
type: SignerType,
result: String,
@@ -599,7 +598,7 @@ object IntentUtils {
// plaintext from `text`, while `result` keeps the wire value.
SignerType.NIP44_V3_ENCRYPT -> {
val plaintext = try {
kotlin.io.encoding.Base64.decode(data).toString(Charsets.UTF_8)
Base64.decode(data).toString(Charsets.UTF_8)
} catch (_: Exception) {
data
}
@@ -607,7 +606,7 @@ object IntentUtils {
}
SignerType.NIP44_V3_DECRYPT -> {
val plaintext = try {
kotlin.io.encoding.Base64.decode(result).toString(Charsets.UTF_8)
Base64.decode(result).toString(Charsets.UTF_8)
} catch (_: Exception) {
result
}
@@ -960,7 +959,7 @@ object IntentUtils {
GZIPOutputStream(bos).use { gzos ->
gzos.write(event.toByteArray())
}
Base64.getEncoder().encodeToString(bos.toByteArray())
Base64.encode(bos.toByteArray())
}
val intent = Intent(Intent.ACTION_VIEW)
@@ -3,12 +3,14 @@ package com.greenart7c3.nostrsigner.service
import android.app.NotificationManager
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.core.content.FileProvider
import com.greenart7c3.nostrsigner.Amber
import com.greenart7c3.nostrsigner.AmberLog
import com.greenart7c3.nostrsigner.BuildConfig
import com.greenart7c3.nostrsigner.BuildFlavorChecker
import com.greenart7c3.nostrsigner.LocalPreferences
import com.greenart7c3.nostrsigner.models.TorMode
import com.greenart7c3.nostrsigner.models.UpdateChannel
import com.greenart7c3.nostrsigner.okhttp.HttpClientManager
import com.vitorpamplona.quartz.nip01Core.core.Event
@@ -224,7 +226,7 @@ class ZapstoreUpdater(
}
private fun isMatchingArch(arch: String): Boolean {
val supportedAbis = android.os.Build.SUPPORTED_ABIS.toList()
val supportedAbis = Build.SUPPORTED_ABIS.toList()
return supportedAbis.any { it.equals(arch, ignoreCase = true) }
}
@@ -277,7 +279,7 @@ class ZapstoreUpdater(
val settings = withContext(Dispatchers.IO) {
LocalPreferences.loadSettingsFromEncryptedStorage()
}
val useProxy = settings.torMode != com.greenart7c3.nostrsigner.models.TorMode.DISABLED
val useProxy = settings.torMode != TorMode.DISABLED
val client = HttpClientManager.getHttpClient(useProxy)
val request = Request.Builder().url(release.url).build()
val response = client.newCall(request).execute()
@@ -72,6 +72,7 @@ import com.greenart7c3.nostrsigner.LocalPreferences
import com.greenart7c3.nostrsigner.R
import com.greenart7c3.nostrsigner.models.Account
import com.greenart7c3.nostrsigner.models.TorMode
import com.greenart7c3.nostrsigner.service.TorManager
import com.greenart7c3.nostrsigner.ui.actions.LogoutDialog
import com.greenart7c3.nostrsigner.ui.components.AmberButton
import com.greenart7c3.nostrsigner.ui.components.TextSpinner
@@ -373,7 +374,7 @@ fun SettingsScreen(
torMode = TorMode.DISABLED
scope.launch(Dispatchers.IO) {
if (Amber.instance.settings.torMode == TorMode.BUILTIN) {
com.greenart7c3.nostrsigner.service.TorManager.stop()
TorManager.stop()
}
LocalPreferences.updateTorMode(context, TorMode.DISABLED)
Amber.instance.checkForNewRelaysAndUpdateAllFilters()
@@ -37,6 +37,7 @@ import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.greenart7c3.nostrsigner.Amber
import com.greenart7c3.nostrsigner.R
@@ -198,7 +199,7 @@ private fun ActivityStatsBar(stats: WindowStats, maxTotal: Long) {
Text(
text = stats.total.toString(),
modifier = Modifier.padding(start = 8.dp),
textAlign = androidx.compose.ui.text.style.TextAlign.End,
textAlign = TextAlign.End,
fontWeight = FontWeight.Medium,
maxLines = 1,
)
@@ -1,5 +1,6 @@
package com.greenart7c3.nostrsigner
import java.net.URI
import kotlin.system.measureNanoTime
import kotlin.system.measureTimeMillis
import kotlinx.coroutines.delay
@@ -178,7 +179,7 @@ class SignerProviderBenchmarkTest {
val warmupIterations = 5_000
fun extractHost(url: String): String = try {
java.net.URI(url).host ?: url
URI(url).host ?: url
} catch (e: Exception) {
url
}
@@ -233,7 +234,7 @@ class SignerProviderBenchmarkTest {
val uri = StringBuilder(prefix + "SIGN_EVENT")
fun extractHost(url: String) = try {
java.net.URI(url).host ?: url
URI(url).host ?: url
} catch (e: Exception) {
url
}
@@ -2,6 +2,7 @@ package com.greenart7c3.nostrsigner.service
import com.greenart7c3.nostrsigner.database.ApplicationPermissionsEntity
import com.vitorpamplona.quartz.utils.TimeUtils
import java.util.Locale
import kotlin.system.measureNanoTime
import org.junit.Test
@@ -278,7 +279,7 @@ class IntentUtilsBeforeAfterTest {
// Warm up
repeat(5_000) {
inputs.forEach { s ->
s.lowercase(java.util.Locale.ROOT)
s.lowercase(Locale.ROOT)
s.lowercase()
}
}
@@ -286,7 +287,7 @@ class IntentUtilsBeforeAfterTest {
val beforeNs = measureNanoTime {
repeat(iterations) {
// OLD equivalent: toLowerCase(Locale.current) — uses java.util.Locale lookup
inputs.forEach { s -> s.lowercase(java.util.Locale.ROOT) }
inputs.forEach { s -> s.lowercase(Locale.ROOT) }
}
}
@@ -3,7 +3,9 @@ package com.greenart7c3.nostrsigner.service.nip44v3
import com.fasterxml.jackson.databind.JsonNode
import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair
import com.vitorpamplona.quartz.nip01Core.jackson.JacksonMapper
import com.vitorpamplona.quartz.utils.Secp256k1Instance
import java.security.MessageDigest
import kotlin.io.encoding.Base64
import org.junit.Assert.assertArrayEquals
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
@@ -66,7 +68,7 @@ class Nip44v3Test {
// Key derivation matches PRK / encryption_key / mac_key from spec
val prk1 = Nip44v3.extract(
com.vitorpamplona.quartz.utils.Secp256k1Instance.pubKeyTweakMulCompact(pub2, priv1),
Secp256k1Instance.pubKeyTweakMulCompact(pub2, priv1),
nonce,
)
assertEquals("vector $idx: prk", expectedPrk, toHex(prk1))
@@ -238,10 +240,10 @@ class Nip44v3Test {
val ownPub = pubKeyFor("0000000000000000000000000000000000000000000000000000000000000001")
val ct = Nip44v3.encrypt("hello".toByteArray(), priv, peerPub, kind = 1, scope = "")
val decoded = kotlin.io.encoding.Base64.decode(ct)
val decoded = Base64.decode(ct)
// Flip a bit in the MAC region (bytes 33..65)
decoded[40] = (decoded[40].toInt() xor 0x01).toByte()
val tampered = kotlin.io.encoding.Base64.encode(decoded)
val tampered = Base64.encode(decoded)
val ex = assertThrows(Nip44v3.Nip44v3Exception::class.java) {
Nip44v3.decrypt(tampered, peer, ownPub, 1, "")
}