add proguard

This commit is contained in:
greenart7c3
2024-05-03 09:05:47 -03:00
parent 3b3094dddb
commit 698195a93d
25 changed files with 310 additions and 272 deletions
+2 -2
View File
@@ -29,8 +29,8 @@ android {
buildTypes { buildTypes {
release { release {
// minifyEnabled false proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), 'proguard-rules.pro'
// proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' minifyEnabled true
resValue "string", "app_name", "@string/app_name_release" resValue "string", "app_name", "@string/app_name_release"
} }
debug { debug {
+21 -21
View File
@@ -11,7 +11,7 @@
"type": "UNIVERSAL", "type": "UNIVERSAL",
"filters": [], "filters": [],
"attributes": [], "attributes": [],
"versionCode": 51, "versionCode": 60,
"versionName": "1.0.0", "versionName": "1.0.0",
"outputFile": "app-play-universal-release.apk" "outputFile": "app-play-universal-release.apk"
}, },
@@ -24,23 +24,10 @@
} }
], ],
"attributes": [], "attributes": [],
"versionCode": 51, "versionCode": 60,
"versionName": "1.0.0", "versionName": "1.0.0",
"outputFile": "app-play-armeabi-v7a-release.apk" "outputFile": "app-play-armeabi-v7a-release.apk"
}, },
{
"type": "ONE_OF_MANY",
"filters": [
{
"filterType": "ABI",
"value": "x86"
}
],
"attributes": [],
"versionCode": 51,
"versionName": "1.0.0",
"outputFile": "app-play-x86-release.apk"
},
{ {
"type": "ONE_OF_MANY", "type": "ONE_OF_MANY",
"filters": [ "filters": [
@@ -50,7 +37,7 @@
} }
], ],
"attributes": [], "attributes": [],
"versionCode": 51, "versionCode": 60,
"versionName": "1.0.0", "versionName": "1.0.0",
"outputFile": "app-play-arm64-v8a-release.apk" "outputFile": "app-play-arm64-v8a-release.apk"
}, },
@@ -63,9 +50,22 @@
} }
], ],
"attributes": [], "attributes": [],
"versionCode": 51, "versionCode": 60,
"versionName": "1.0.0", "versionName": "1.0.0",
"outputFile": "app-play-x86_64-release.apk" "outputFile": "app-play-x86_64-release.apk"
},
{
"type": "ONE_OF_MANY",
"filters": [
{
"filterType": "ABI",
"value": "x86"
}
],
"attributes": [],
"versionCode": 60,
"versionName": "1.0.0",
"outputFile": "app-play-x86-release.apk"
} }
], ],
"elementType": "File", "elementType": "File",
@@ -76,9 +76,9 @@
"baselineProfiles": [ "baselineProfiles": [
"baselineProfiles/1/app-play-universal-release.dm", "baselineProfiles/1/app-play-universal-release.dm",
"baselineProfiles/1/app-play-armeabi-v7a-release.dm", "baselineProfiles/1/app-play-armeabi-v7a-release.dm",
"baselineProfiles/1/app-play-x86-release.dm",
"baselineProfiles/1/app-play-arm64-v8a-release.dm", "baselineProfiles/1/app-play-arm64-v8a-release.dm",
"baselineProfiles/1/app-play-x86_64-release.dm" "baselineProfiles/1/app-play-x86_64-release.dm",
"baselineProfiles/1/app-play-x86-release.dm"
] ]
}, },
{ {
@@ -87,9 +87,9 @@
"baselineProfiles": [ "baselineProfiles": [
"baselineProfiles/0/app-play-universal-release.dm", "baselineProfiles/0/app-play-universal-release.dm",
"baselineProfiles/0/app-play-armeabi-v7a-release.dm", "baselineProfiles/0/app-play-armeabi-v7a-release.dm",
"baselineProfiles/0/app-play-x86-release.dm",
"baselineProfiles/0/app-play-arm64-v8a-release.dm", "baselineProfiles/0/app-play-arm64-v8a-release.dm",
"baselineProfiles/0/app-play-x86_64-release.dm" "baselineProfiles/0/app-play-x86_64-release.dm",
"baselineProfiles/0/app-play-x86-release.dm"
] ]
} }
], ],
+13
View File
@@ -33,6 +33,11 @@
# JNA For Libsodium # JNA For Libsodium
-keep class com.goterl.lazysodium.** { *; } -keep class com.goterl.lazysodium.** { *; }
# libscrypt
-keep class com.lambdaworks.codec.** { *; }
-keep class com.lambdaworks.crypto.** { *; }
-keep class com.lambdaworks.jni.** { *; }
# JNA also requires AWT, which Android does not have. So the classes are broken down to filter AWT out # JNA also requires AWT, which Android does not have. So the classes are broken down to filter AWT out
-keep class com.sun.jna.ToNativeConverter { *; } -keep class com.sun.jna.ToNativeConverter { *; }
-keep class com.sun.jna.NativeMapped { *; } -keep class com.sun.jna.NativeMapped { *; }
@@ -58,3 +63,11 @@
-keep class com.vitorpamplona.quartz.events.** { *; } -keep class com.vitorpamplona.quartz.events.** { *; }
-keep class com.vitorpamplona.amethyst.model.** { *; } -keep class com.vitorpamplona.amethyst.model.** { *; }
-keep class com.vitorpamplona.amethyst.service.** { *; } -keep class com.vitorpamplona.amethyst.service.** { *; }
-keep class com.greenart7c3.nostrsigner.models.** { *; }
-keep class com.greenart7c3.nostrsigner.service.** { *; }
-dontwarn edu.umd.cs.findbugs.annotations.NonNull
-dontwarn edu.umd.cs.findbugs.annotations.Nullable
-dontwarn edu.umd.cs.findbugs.annotations.SuppressFBWarnings
-dontwarn java.lang.instrument.ClassDefinition
-dontwarn java.lang.instrument.UnmodifiableClassException
@@ -2,9 +2,6 @@ package com.greenart7c3.nostrsigner
import android.content.Intent import android.content.Intent
import android.net.ConnectivityManager import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
@@ -12,35 +9,19 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import com.greenart7c3.nostrsigner.models.IntentData
import com.greenart7c3.nostrsigner.service.HttpClientManager
import com.greenart7c3.nostrsigner.service.IntentUtils
import com.greenart7c3.nostrsigner.service.NotificationDataSource
import com.greenart7c3.nostrsigner.ui.AccountScreen import com.greenart7c3.nostrsigner.ui.AccountScreen
import com.greenart7c3.nostrsigner.ui.AccountStateViewModel import com.greenart7c3.nostrsigner.ui.AccountStateViewModel
import com.greenart7c3.nostrsigner.ui.navigation.Route
import com.greenart7c3.nostrsigner.ui.theme.NostrSignerTheme import com.greenart7c3.nostrsigner.ui.theme.NostrSignerTheme
import com.vitorpamplona.quartz.encoders.toNpub
import fr.acinq.secp256k1.Hex
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
fun Intent.isLaunchFromHistory(): Boolean = fun Intent.isLaunchFromHistory(): Boolean =
this.flags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY == Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY this.flags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY == Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
private val intents = MutableStateFlow<List<IntentData>>(listOf()) private val mainViewModel = MainViewModel()
val isOnMobileDataState = mutableStateOf(false)
private val isOnWifiDataState = mutableStateOf(false)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -67,167 +48,42 @@ class MainActivity : AppCompatActivity() {
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background, color = MaterialTheme.colorScheme.background,
) { ) {
val npub = intent.getStringExtra("current_user") ?: getAccount() val npub = intent.getStringExtra("current_user") ?: mainViewModel.getAccount()
val accountStateViewModel: AccountStateViewModel = val accountStateViewModel: AccountStateViewModel =
viewModel { viewModel {
AccountStateViewModel(npub) AccountStateViewModel(npub)
} }
AccountScreen(accountStateViewModel, intent, packageName, appName, intents) AccountScreen(accountStateViewModel, intent, packageName, appName, mainViewModel.intents)
} }
} }
} }
} }
fun getAccount(): String? {
val pubKeys =
intents.value.mapNotNull {
it.event?.pubKey
}
if (pubKeys.isEmpty()) return null
return Hex.decode(pubKeys.first()).toNpub()
}
@OptIn(DelicateCoroutinesApi::class)
override fun onResume() { override fun onResume() {
val requests = mainViewModel.showBunkerRequests(callingPackage)
IntentUtils.bunkerRequests.map {
it.value.copy()
}
GlobalScope.launch(Dispatchers.IO) {
val account = LocalPreferences.loadFromEncryptedStorage()
account?.let { acc ->
requests.forEach {
val contentIntent =
Intent(applicationContext, MainActivity::class.java).apply {
data = Uri.parse("nostrsigner:")
}
contentIntent.putExtra("bunker", it.toJson())
contentIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
IntentUtils.getIntentData(contentIntent, callingPackage, Route.Home.route, acc) { intentData ->
if (intentData != null) {
if (intents.value.none { item -> item.id == intentData.id }) {
intents.value += listOf(intentData)
}
}
}
}
}
IntentUtils.bunkerRequests.clear()
}
if (BuildConfig.FLAVOR != "offline") { if (BuildConfig.FLAVOR != "offline") {
val connectivityManager = val connectivityManager =
(getSystemService(ConnectivityManager::class.java) as ConnectivityManager) (getSystemService(ConnectivityManager::class.java) as ConnectivityManager)
connectivityManager.registerDefaultNetworkCallback(networkCallback) connectivityManager.registerDefaultNetworkCallback(mainViewModel.networkCallback)
connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)?.let { connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)?.let {
updateNetworkCapabilities(it) mainViewModel.updateNetworkCapabilities(it)
} }
} }
super.onResume() super.onResume()
} }
@OptIn(DelicateCoroutinesApi::class)
override fun onNewIntent(intent: Intent) { override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent) super.onNewIntent(intent)
GlobalScope.launch(Dispatchers.IO) { mainViewModel.onNewIntent(intent, callingPackage)
val account = LocalPreferences.loadFromEncryptedStorage()
account?.let { acc ->
IntentUtils.getIntentData(intent, callingPackage, intent.getStringExtra("route"), acc) { intentData ->
if (intentData != null) {
if (intents.value.none { item -> item.id == intentData.id }) {
intents.value += listOf(intentData)
}
intents.value =
intents.value.map {
it.copy()
}.toMutableList()
}
}
}
}
} }
override fun onDestroy() { override fun onDestroy() {
intents.value = emptyList() mainViewModel.intents.value = emptyList()
super.onDestroy() super.onDestroy()
} }
fun updateNetworkCapabilities(networkCapabilities: NetworkCapabilities): Boolean {
val isOnMobileData = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
val isOnWifi = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
var changedNetwork = false
if (isOnMobileDataState.value != isOnMobileData) {
isOnMobileDataState.value = isOnMobileData
changedNetwork = true
}
if (isOnWifiDataState.value != isOnWifi) {
isOnWifiDataState.value = isOnWifi
changedNetwork = true
}
if (changedNetwork) {
if (isOnMobileData) {
HttpClientManager.setDefaultTimeout(HttpClientManager.DEFAULT_TIMEOUT_ON_MOBILE)
} else {
HttpClientManager.setDefaultTimeout(HttpClientManager.DEFAULT_TIMEOUT_ON_WIFI)
}
}
return changedNetwork
}
@OptIn(DelicateCoroutinesApi::class)
private val networkCallback =
object : ConnectivityManager.NetworkCallback() {
var lastNetwork: Network? = null
override fun onAvailable(network: Network) {
super.onAvailable(network)
if (BuildConfig.FLAVOR == "offline") return
if (lastNetwork != null && lastNetwork != network) {
GlobalScope.launch(Dispatchers.IO) {
NotificationDataSource.stopSync()
delay(1000)
NotificationDataSource.start()
}
}
lastNetwork = network
}
// Network capabilities have changed for the network
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities,
) {
super.onCapabilitiesChanged(network, networkCapabilities)
if (BuildConfig.FLAVOR == "offline") return
GlobalScope.launch(Dispatchers.IO) {
Log.d(
"ServiceManager NetworkCallback",
"onCapabilitiesChanged: ${network.networkHandle} hasMobileData ${isOnMobileDataState.value} hasWifi ${isOnWifiDataState.value}",
)
if (updateNetworkCapabilities(networkCapabilities)) {
NotificationDataSource.stopSync()
delay(1000)
NotificationDataSource.start()
}
}
}
}
} }
@@ -0,0 +1,162 @@
package com.greenart7c3.nostrsigner
import android.content.Intent
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.net.Uri
import android.util.Log
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.greenart7c3.nostrsigner.models.IntentData
import com.greenart7c3.nostrsigner.service.HttpClientManager
import com.greenart7c3.nostrsigner.service.IntentUtils
import com.greenart7c3.nostrsigner.service.NotificationDataSource
import com.greenart7c3.nostrsigner.ui.NotificationType
import com.greenart7c3.nostrsigner.ui.navigation.Route
import com.vitorpamplona.quartz.encoders.toNpub
import fr.acinq.secp256k1.Hex
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
class MainViewModel : ViewModel() {
val intents = MutableStateFlow<List<IntentData>>(listOf())
val isOnMobileDataState = mutableStateOf(false)
val isOnWifiDataState = mutableStateOf(false)
val networkCallback =
object : ConnectivityManager.NetworkCallback() {
var lastNetwork: Network? = null
override fun onAvailable(network: Network) {
super.onAvailable(network)
if (BuildConfig.FLAVOR == "offline") return
if (lastNetwork != null && lastNetwork != network && LocalPreferences.getNotificationType() == NotificationType.DIRECT) {
viewModelScope.launch(Dispatchers.IO) {
NotificationDataSource.stopSync()
delay(1000)
NotificationDataSource.start()
}
}
lastNetwork = network
}
// Network capabilities have changed for the network
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities,
) {
super.onCapabilitiesChanged(network, networkCapabilities)
if (BuildConfig.FLAVOR == "offline") return
viewModelScope.launch(Dispatchers.IO) {
Log.d(
"ServiceManager NetworkCallback",
"onCapabilitiesChanged: ${network.networkHandle} hasMobileData ${isOnMobileDataState.value} hasWifi ${isOnWifiDataState.value}",
)
if (updateNetworkCapabilities(networkCapabilities) && LocalPreferences.getNotificationType() == NotificationType.DIRECT) {
NotificationDataSource.stopSync()
delay(1000)
NotificationDataSource.start()
}
}
}
}
fun getAccount(): String? {
val pubKeys =
intents.value.mapNotNull {
it.event?.pubKey
}
if (pubKeys.isEmpty()) return null
return Hex.decode(pubKeys.first()).toNpub()
}
fun showBunkerRequests(callingPackage: String?) {
val requests =
IntentUtils.bunkerRequests.map {
it.value.copy()
}
viewModelScope.launch(Dispatchers.IO) {
val account = LocalPreferences.loadFromEncryptedStorage()
account?.let { acc ->
requests.forEach {
val contentIntent =
Intent(NostrSigner.instance, MainActivity::class.java).apply {
data = Uri.parse("nostrsigner:")
}
contentIntent.putExtra("bunker", it.toJson())
contentIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
IntentUtils.getIntentData(contentIntent, callingPackage, Route.Home.route, acc) { intentData ->
if (intentData != null) {
if (intents.value.none { item -> item.id == intentData.id }) {
intents.value += listOf(intentData)
}
}
}
}
}
IntentUtils.bunkerRequests.clear()
}
}
fun onNewIntent(
intent: Intent,
callingPackage: String?,
) {
viewModelScope.launch(Dispatchers.IO) {
val account = LocalPreferences.loadFromEncryptedStorage()
account?.let { acc ->
IntentUtils.getIntentData(intent, callingPackage, intent.getStringExtra("route"), acc) { intentData ->
if (intentData != null) {
if (intents.value.none { item -> item.id == intentData.id }) {
intents.value += listOf(intentData)
}
intents.value =
intents.value.map {
it.copy()
}.toMutableList()
}
}
}
}
}
fun updateNetworkCapabilities(networkCapabilities: NetworkCapabilities): Boolean {
val isOnMobileData = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
val isOnWifi = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
var changedNetwork = false
if (isOnMobileDataState.value != isOnMobileData) {
isOnMobileDataState.value = isOnMobileData
changedNetwork = true
}
if (isOnWifiDataState.value != isOnWifi) {
isOnWifiDataState.value = isOnWifi
changedNetwork = true
}
if (changedNetwork) {
if (isOnMobileData) {
HttpClientManager.setDefaultTimeout(HttpClientManager.DEFAULT_TIMEOUT_ON_MOBILE)
} else {
HttpClientManager.setDefaultTimeout(HttpClientManager.DEFAULT_TIMEOUT_ON_WIFI)
}
}
return changedNetwork
}
}
@@ -0,0 +1,87 @@
package com.greenart7c3.nostrsigner.models
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.deser.std.StdDeserializer
import com.fasterxml.jackson.databind.module.SimpleModule
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
data class BunkerRequest(
val id: String,
val method: String,
val params: Array<String>,
var localKey: String,
var relays: List<String>,
var secret: String,
var currentAccount: String,
) {
fun toJson(): String {
return mapper.writeValueAsString(this)
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as BunkerRequest
if (id != other.id) return false
if (method != other.method) return false
if (!params.contentEquals(other.params)) return false
if (localKey != other.localKey) return false
if (relays != other.relays) return false
if (secret != other.secret) return false
return true
}
override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + method.hashCode()
result = 31 * result + params.contentHashCode()
result = 31 * result + localKey.hashCode()
result = 31 * result + relays.hashCode()
result = 31 * result + secret.hashCode()
return result
}
companion object {
val mapper: ObjectMapper =
jacksonObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.registerModule(
SimpleModule()
.addDeserializer(BunkerRequest::class.java, BunkerRequestDeserializer()),
)
fun fromJson(jsonObject: JsonNode): BunkerRequest {
return BunkerRequest(
id = jsonObject.get("id").asText().intern(),
method = jsonObject.get("method").asText().intern(),
params =
jsonObject.get("params").asIterable().toList().map {
it.asText().intern()
}.toTypedArray(),
localKey = jsonObject.get("localKey")?.asText()?.intern() ?: "",
relays =
jsonObject.get("relays")?.asIterable()?.toList()?.map {
it.asText().intern()
} ?: listOf(),
secret = jsonObject.get("secret")?.asText()?.intern() ?: "",
currentAccount = jsonObject.get("currentAccount")?.asText()?.intern() ?: "",
)
}
private class BunkerRequestDeserializer : StdDeserializer<BunkerRequest>(BunkerRequest::class.java) {
override fun deserialize(
jp: JsonParser,
ctxt: DeserializationContext,
): BunkerRequest {
return fromJson(jp.codec.readTree(jp))
}
}
}
}
@@ -0,0 +1,7 @@
package com.greenart7c3.nostrsigner.models
data class BunkerResponse(
val id: String,
val result: String,
val error: String?,
)
@@ -1,7 +1,6 @@
package com.greenart7c3.nostrsigner.models package com.greenart7c3.nostrsigner.models
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
import com.greenart7c3.nostrsigner.service.BunkerRequest
import com.vitorpamplona.quartz.encoders.HexKey import com.vitorpamplona.quartz.encoders.HexKey
import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.events.Event
@@ -7,10 +7,11 @@ import com.greenart7c3.nostrsigner.database.ApplicationEntity
import com.greenart7c3.nostrsigner.database.ApplicationPermissionsEntity import com.greenart7c3.nostrsigner.database.ApplicationPermissionsEntity
import com.greenart7c3.nostrsigner.database.ApplicationWithPermissions import com.greenart7c3.nostrsigner.database.ApplicationWithPermissions
import com.greenart7c3.nostrsigner.models.Account import com.greenart7c3.nostrsigner.models.Account
import com.greenart7c3.nostrsigner.models.BunkerRequest
import com.greenart7c3.nostrsigner.models.BunkerResponse
import com.greenart7c3.nostrsigner.models.IntentData import com.greenart7c3.nostrsigner.models.IntentData
import com.greenart7c3.nostrsigner.models.SignerType import com.greenart7c3.nostrsigner.models.SignerType
import com.greenart7c3.nostrsigner.relays.Relay import com.greenart7c3.nostrsigner.relays.Relay
import com.greenart7c3.nostrsigner.ui.BunkerResponse
import com.vitorpamplona.quartz.crypto.CryptoUtils import com.vitorpamplona.quartz.crypto.CryptoUtils
import com.vitorpamplona.quartz.encoders.HexKey import com.vitorpamplona.quartz.encoders.HexKey
import com.vitorpamplona.quartz.encoders.hexToByteArray import com.vitorpamplona.quartz.encoders.hexToByteArray
@@ -49,7 +49,7 @@ class ConnectivityService : Service() {
override fun onCreate() { override fun onCreate() {
startForeground(1, createNotification()) startForeground(1, createNotification())
timer.scheduleAtFixedRate( timer.schedule(
object : TimerTask() { object : TimerTask() {
override fun run() { override fun run() {
if (LocalPreferences.getNotificationType() == NotificationType.PUSH) return if (LocalPreferences.getNotificationType() == NotificationType.PUSH) return
@@ -27,109 +27,25 @@ import android.util.Log
import androidx.compose.ui.text.intl.Locale import androidx.compose.ui.text.intl.Locale
import androidx.compose.ui.text.toLowerCase import androidx.compose.ui.text.toLowerCase
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.deser.std.StdDeserializer
import com.fasterxml.jackson.databind.module.SimpleModule
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.greenart7c3.nostrsigner.BuildConfig import com.greenart7c3.nostrsigner.BuildConfig
import com.greenart7c3.nostrsigner.LocalPreferences import com.greenart7c3.nostrsigner.LocalPreferences
import com.greenart7c3.nostrsigner.NostrSigner import com.greenart7c3.nostrsigner.NostrSigner
import com.greenart7c3.nostrsigner.database.ApplicationWithPermissions import com.greenart7c3.nostrsigner.database.ApplicationWithPermissions
import com.greenart7c3.nostrsigner.database.NotificationEntity import com.greenart7c3.nostrsigner.database.NotificationEntity
import com.greenart7c3.nostrsigner.models.Account import com.greenart7c3.nostrsigner.models.Account
import com.greenart7c3.nostrsigner.models.BunkerRequest
import com.greenart7c3.nostrsigner.models.BunkerResponse
import com.greenart7c3.nostrsigner.models.Permission import com.greenart7c3.nostrsigner.models.Permission
import com.greenart7c3.nostrsigner.models.SignerType import com.greenart7c3.nostrsigner.models.SignerType
import com.greenart7c3.nostrsigner.relays.Relay import com.greenart7c3.nostrsigner.relays.Relay
import com.greenart7c3.nostrsigner.service.NotificationUtils.sendNotification import com.greenart7c3.nostrsigner.service.NotificationUtils.sendNotification
import com.greenart7c3.nostrsigner.service.model.AmberEvent import com.greenart7c3.nostrsigner.service.model.AmberEvent
import com.greenart7c3.nostrsigner.ui.BunkerResponse
import com.greenart7c3.nostrsigner.ui.NotificationType import com.greenart7c3.nostrsigner.ui.NotificationType
import com.vitorpamplona.quartz.encoders.toNpub import com.vitorpamplona.quartz.encoders.toNpub
import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.events.Event
import com.vitorpamplona.quartz.events.GiftWrapEvent import com.vitorpamplona.quartz.events.GiftWrapEvent
import com.vitorpamplona.quartz.events.SealedGossipEvent import com.vitorpamplona.quartz.events.SealedGossipEvent
data class BunkerRequest(
val id: String,
val method: String,
val params: Array<String>,
var localKey: String,
var relays: List<String>,
var secret: String,
var currentAccount: String,
) {
fun toJson(): String {
return mapper.writeValueAsString(this)
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as BunkerRequest
if (id != other.id) return false
if (method != other.method) return false
if (!params.contentEquals(other.params)) return false
if (localKey != other.localKey) return false
if (relays != other.relays) return false
if (secret != other.secret) return false
return true
}
override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + method.hashCode()
result = 31 * result + params.contentHashCode()
result = 31 * result + localKey.hashCode()
result = 31 * result + relays.hashCode()
result = 31 * result + secret.hashCode()
return result
}
companion object {
val mapper: ObjectMapper =
jacksonObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.registerModule(
SimpleModule()
.addDeserializer(BunkerRequest::class.java, BunkerRequestDeserializer()),
)
fun fromJson(jsonObject: JsonNode): BunkerRequest {
return BunkerRequest(
id = jsonObject.get("id").asText().intern(),
method = jsonObject.get("method").asText().intern(),
params =
jsonObject.get("params").asIterable().toList().map {
it.asText().intern()
}.toTypedArray(),
localKey = jsonObject.get("localKey")?.asText()?.intern() ?: "",
relays =
jsonObject.get("relays")?.asIterable()?.toList()?.map {
it.asText().intern()
} ?: listOf(),
secret = jsonObject.get("secret")?.asText()?.intern() ?: "",
currentAccount = jsonObject.get("currentAccount")?.asText()?.intern() ?: "",
)
}
private class BunkerRequestDeserializer : StdDeserializer<BunkerRequest>(BunkerRequest::class.java) {
override fun deserialize(
jp: JsonParser,
ctxt: DeserializationContext,
): BunkerRequest {
return fromJson(jp.codec.readTree(jp))
}
}
}
}
class EventNotificationConsumer(private val applicationContext: Context) { class EventNotificationConsumer(private val applicationContext: Context) {
private val groupKey = "com.greenart7c3.nostrsigner.DM_NOTIFICATION" private val groupKey = "com.greenart7c3.nostrsigner.DM_NOTIFICATION"
@@ -15,6 +15,8 @@ import com.google.gson.reflect.TypeToken
import com.greenart7c3.nostrsigner.LocalPreferences import com.greenart7c3.nostrsigner.LocalPreferences
import com.greenart7c3.nostrsigner.NostrSigner import com.greenart7c3.nostrsigner.NostrSigner
import com.greenart7c3.nostrsigner.models.Account import com.greenart7c3.nostrsigner.models.Account
import com.greenart7c3.nostrsigner.models.BunkerRequest
import com.greenart7c3.nostrsigner.models.BunkerResponse
import com.greenart7c3.nostrsigner.models.CompressionType import com.greenart7c3.nostrsigner.models.CompressionType
import com.greenart7c3.nostrsigner.models.IntentData import com.greenart7c3.nostrsigner.models.IntentData
import com.greenart7c3.nostrsigner.models.Permission import com.greenart7c3.nostrsigner.models.Permission
@@ -25,7 +27,6 @@ import com.greenart7c3.nostrsigner.relays.Client
import com.greenart7c3.nostrsigner.relays.Relay import com.greenart7c3.nostrsigner.relays.Relay
import com.greenart7c3.nostrsigner.relays.RelayPool import com.greenart7c3.nostrsigner.relays.RelayPool
import com.greenart7c3.nostrsigner.service.model.AmberEvent import com.greenart7c3.nostrsigner.service.model.AmberEvent
import com.greenart7c3.nostrsigner.ui.BunkerResponse
import com.greenart7c3.nostrsigner.ui.NotificationType import com.greenart7c3.nostrsigner.ui.NotificationType
import com.vitorpamplona.quartz.encoders.toHexKey import com.vitorpamplona.quartz.encoders.toHexKey
import com.vitorpamplona.quartz.encoders.toNpub import com.vitorpamplona.quartz.encoders.toNpub
@@ -32,6 +32,7 @@ import android.service.notification.StatusBarNotification
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import com.greenart7c3.nostrsigner.MainActivity import com.greenart7c3.nostrsigner.MainActivity
import com.greenart7c3.nostrsigner.R import com.greenart7c3.nostrsigner.R
import com.greenart7c3.nostrsigner.models.BunkerRequest
import com.greenart7c3.nostrsigner.ui.navigation.Route import com.greenart7c3.nostrsigner.ui.navigation.Route
object NotificationUtils { object NotificationUtils {
@@ -86,6 +86,7 @@ import com.greenart7c3.nostrsigner.database.ApplicationEntity
import com.greenart7c3.nostrsigner.database.ApplicationPermissionsEntity import com.greenart7c3.nostrsigner.database.ApplicationPermissionsEntity
import com.greenart7c3.nostrsigner.database.ApplicationWithPermissions import com.greenart7c3.nostrsigner.database.ApplicationWithPermissions
import com.greenart7c3.nostrsigner.models.Account import com.greenart7c3.nostrsigner.models.Account
import com.greenart7c3.nostrsigner.models.BunkerResponse
import com.greenart7c3.nostrsigner.models.CompressionType import com.greenart7c3.nostrsigner.models.CompressionType
import com.greenart7c3.nostrsigner.models.IntentData import com.greenart7c3.nostrsigner.models.IntentData
import com.greenart7c3.nostrsigner.models.Permission import com.greenart7c3.nostrsigner.models.Permission
@@ -113,12 +114,6 @@ import java.util.Base64
import java.util.UUID import java.util.UUID
import java.util.zip.GZIPOutputStream import java.util.zip.GZIPOutputStream
data class BunkerResponse(
val id: String,
val result: String,
val error: String?,
)
@OptIn(DelicateCoroutinesApi::class) @OptIn(DelicateCoroutinesApi::class)
fun sendResult( fun sendResult(
context: Context, context: Context,
@@ -48,6 +48,7 @@ import com.greenart7c3.nostrsigner.NostrSigner
import com.greenart7c3.nostrsigner.R import com.greenart7c3.nostrsigner.R
import com.greenart7c3.nostrsigner.database.AppDatabase import com.greenart7c3.nostrsigner.database.AppDatabase
import com.greenart7c3.nostrsigner.models.Account import com.greenart7c3.nostrsigner.models.Account
import com.greenart7c3.nostrsigner.models.BunkerResponse
import com.greenart7c3.nostrsigner.models.IntentData import com.greenart7c3.nostrsigner.models.IntentData
import com.greenart7c3.nostrsigner.models.Permission import com.greenart7c3.nostrsigner.models.Permission
import com.greenart7c3.nostrsigner.models.SignerType import com.greenart7c3.nostrsigner.models.SignerType
@@ -62,7 +63,6 @@ import com.greenart7c3.nostrsigner.service.RelayDisconnectService
import com.greenart7c3.nostrsigner.service.getAppCompatActivity import com.greenart7c3.nostrsigner.service.getAppCompatActivity
import com.greenart7c3.nostrsigner.service.model.AmberEvent import com.greenart7c3.nostrsigner.service.model.AmberEvent
import com.greenart7c3.nostrsigner.service.toShortenHex import com.greenart7c3.nostrsigner.service.toShortenHex
import com.greenart7c3.nostrsigner.ui.BunkerResponse
import com.greenart7c3.nostrsigner.ui.Result import com.greenart7c3.nostrsigner.ui.Result
import com.greenart7c3.nostrsigner.ui.theme.ButtonBorder import com.greenart7c3.nostrsigner.ui.theme.ButtonBorder
import com.vitorpamplona.quartz.events.LnZapRequestEvent import com.vitorpamplona.quartz.events.LnZapRequestEvent