From 2230807a19b11906a2dde263e462c11bde68a778 Mon Sep 17 00:00:00 2001 From: koalasat Date: Thu, 24 Oct 2024 17:49:44 +0200 Subject: [PATCH] Integrate Amber --- app/build.gradle.kts | 1 + .../java/com/koalasat/pokey/MainActivity.kt | 47 ++++++++++++++++++- app/src/main/java/com/koalasat/pokey/Pokey.kt | 3 ++ .../koalasat/pokey/models/EncryptedStorage.kt | 21 +++++++-- .../pokey/service/NotificationsService.kt | 27 +++++------ .../koalasat/pokey/ui/home/HomeViewModel.kt | 28 +++++------ gradle/libs.versions.toml | 1 + 7 files changed, 94 insertions(+), 34 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 0682d2e..0c412d7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -124,6 +124,7 @@ dependencies { implementation(libs.androidx.lifecycle.livedata.ktx) implementation(libs.androidx.lifecycle.viewmodel.ktx) implementation(libs.androidx.navigation.fragment.ktx) + implementation(libs.androidx.activity.ktx) implementation(libs.lifecycle.runtime.compose) implementation(libs.lifecycle.viewmodel.compose) implementation(libs.lifecycle.runtime.ktx) diff --git a/app/src/main/java/com/koalasat/pokey/MainActivity.kt b/app/src/main/java/com/koalasat/pokey/MainActivity.kt index 3397432..58779b2 100644 --- a/app/src/main/java/com/koalasat/pokey/MainActivity.kt +++ b/app/src/main/java/com/koalasat/pokey/MainActivity.kt @@ -1,10 +1,13 @@ package com.koalasat.pokey import android.Manifest +import android.app.Activity import android.content.pm.PackageManager import android.os.Build import android.os.Bundle +import android.util.Log import android.widget.Toast +import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat @@ -14,6 +17,11 @@ import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupWithNavController import com.google.android.material.bottomnavigation.BottomNavigationView import com.koalasat.pokey.databinding.ActivityMainBinding +import com.koalasat.pokey.models.EncryptedStorage +import com.vitorpamplona.quartz.signers.ExternalSignerLauncher +import com.vitorpamplona.quartz.signers.SignerType +import java.util.UUID +import kotlin.coroutines.cancellation.CancellationException class MainActivity : AppCompatActivity() { private val requestCodePostNotifications: Int = 1 @@ -22,6 +30,8 @@ class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + EncryptedStorage.init(this) + binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) @@ -52,6 +62,8 @@ class MainActivity : AppCompatActivity() { requestCodePostNotifications, ) } + + if (EncryptedStorage.pubKey.value.isNullOrEmpty()) connectExternalSigner() } override fun onRequestPermissionsResult( @@ -64,9 +76,42 @@ class MainActivity : AppCompatActivity() { if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // Permission granted } else { - // Permission denied, handle accordingly Toast.makeText(applicationContext, getString(R.string.permissions_required), Toast.LENGTH_SHORT).show() } } } + + private fun connectExternalSigner() { + val id = UUID.randomUUID().toString() + val externalSignerLauncher = ExternalSignerLauncher("", signerPackageName = "") + + val nostrSignerLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode != Activity.RESULT_OK) { + Log.e("Pokey", "ExternalSigner result error: ${result.resultCode}") + } else { + result.data?.let { externalSignerLauncher.newResult(it) } + } + } + externalSignerLauncher.registerLauncher( + launcher = { + try { + nostrSignerLauncher.launch(it) // This can remain if you still need to launch it + } catch (e: Exception) { + if (e is CancellationException) throw e + Log.e("Pokey", "Error opening Signer app", e) + } + }, + contentResolver = { Pokey.getInstance().contentResolverFn() }, + ) + externalSignerLauncher.openSignerApp( + "", + SignerType.GET_PUBLIC_KEY, + "", + id, + ) { result -> + val split = result.split("-") + val pubkey = split.first() + if (split.first().isNotEmpty()) EncryptedStorage.updatePubKey(pubkey) + } + } } diff --git a/app/src/main/java/com/koalasat/pokey/Pokey.kt b/app/src/main/java/com/koalasat/pokey/Pokey.kt index f6a289d..e2a7dc4 100644 --- a/app/src/main/java/com/koalasat/pokey/Pokey.kt +++ b/app/src/main/java/com/koalasat/pokey/Pokey.kt @@ -1,6 +1,7 @@ package com.koalasat.pokey import android.app.Application +import android.content.ContentResolver import android.content.Context import android.content.Intent import android.content.SharedPreferences @@ -47,6 +48,8 @@ class Pokey : Application() { saveForegroundServicePreference(this, false) } + fun contentResolverFn(): ContentResolver = contentResolver + companion object { private val _isEnabled = MutableLiveData(false) val isEnabled: LiveData get() = _isEnabled diff --git a/app/src/main/java/com/koalasat/pokey/models/EncryptedStorage.kt b/app/src/main/java/com/koalasat/pokey/models/EncryptedStorage.kt index 277d4e0..e499e05 100644 --- a/app/src/main/java/com/koalasat/pokey/models/EncryptedStorage.kt +++ b/app/src/main/java/com/koalasat/pokey/models/EncryptedStorage.kt @@ -1,25 +1,31 @@ package com.koalasat.pokey.models +import android.content.Context +import android.content.SharedPreferences +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData import androidx.security.crypto.EncryptedSharedPreferences import androidx.security.crypto.MasterKey -import com.koalasat.pokey.Pokey object PrefKeys { const val NOSTR_PUBKEY = "nostr_pubkey" - const val NOSTR_RELAYS = "nostr_relays" } object EncryptedStorage { private const val PREFERENCES_NAME = "secret_keeper" - fun preferences(): EncryptedSharedPreferences { - val context = Pokey.getInstance() + private lateinit var sharedPreferences: SharedPreferences + + private val _pubKey = MutableLiveData() + val pubKey: LiveData get() = _pubKey + + fun init(context: Context) { val masterKey: MasterKey = MasterKey.Builder(context, MasterKey.DEFAULT_MASTER_KEY_ALIAS) .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) .build() - return EncryptedSharedPreferences.create( + sharedPreferences = EncryptedSharedPreferences.create( context, PREFERENCES_NAME, masterKey, @@ -27,4 +33,9 @@ object EncryptedStorage { EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM, ) as EncryptedSharedPreferences } + + fun updatePubKey(newValue: String) { + sharedPreferences.edit().putString(PrefKeys.NOSTR_PUBKEY, newValue).apply() + _pubKey.value = newValue + } } diff --git a/app/src/main/java/com/koalasat/pokey/service/NotificationsService.kt b/app/src/main/java/com/koalasat/pokey/service/NotificationsService.kt index a1efc01..3897a90 100644 --- a/app/src/main/java/com/koalasat/pokey/service/NotificationsService.kt +++ b/app/src/main/java/com/koalasat/pokey/service/NotificationsService.kt @@ -17,8 +17,7 @@ import com.koalasat.pokey.R import com.koalasat.pokey.database.AppDatabase import com.koalasat.pokey.database.NotificationEntity import com.koalasat.pokey.database.RelayEntity -import com.koalasat.pokey.models.EncryptedStorage.preferences -import com.koalasat.pokey.models.PrefKeys +import com.koalasat.pokey.models.EncryptedStorage import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES import com.vitorpamplona.ammolite.relays.Client import com.vitorpamplona.ammolite.relays.EVENT_FINDER_TYPES @@ -332,7 +331,7 @@ class NotificationsService : Service() { var title = "" var text = "" - val pubKey = preferences().getString(PrefKeys.NOSTR_PUBKEY, "") + val pubKey = EncryptedStorage.pubKey if (event.kind == 1) { title = if (event.content().contains("nostr:$pubKey")) { @@ -366,16 +365,16 @@ class NotificationsService : Service() { private fun displayNoteNotification(title: String, text: String, event: Event) { val deepLinkIntent = Intent(Intent.ACTION_VIEW).apply { - val nPub = Nip19Bech32.parseComponents( - "npub", - event.pubKey, - null, - ) - - if (nPub != null) { - Log.d("Pokey", "nostr:${nPub.nip19raw}") - data = Uri.parse("nostr:${nPub.nip19raw}") - } +// val nPub = Nip19Bech32.parseComponents( +// "npub", +// event.pubKey, +// null, +// ) + +// if (nPub != null) { +// data = Uri.parse("nostr:${nPub.nip19raw}") +// } + data = Uri.parse("nostr:") } val pendingIntent = PendingIntent.getActivity( this@NotificationsService, @@ -402,7 +401,7 @@ class NotificationsService : Service() { } private fun getHexKey(): String { - val pubKey = preferences().getString(PrefKeys.NOSTR_PUBKEY, "").toString() + val pubKey = EncryptedStorage.pubKey.value var hexKey = "" val parseReturn = uriToRoute(pubKey) when (val parsed = parseReturn?.entity) { diff --git a/app/src/main/java/com/koalasat/pokey/ui/home/HomeViewModel.kt b/app/src/main/java/com/koalasat/pokey/ui/home/HomeViewModel.kt index b5589e2..b066dae 100644 --- a/app/src/main/java/com/koalasat/pokey/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/koalasat/pokey/ui/home/HomeViewModel.kt @@ -4,27 +4,29 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import com.koalasat.pokey.Pokey -import com.koalasat.pokey.models.EncryptedStorage.preferences -import com.koalasat.pokey.models.PrefKeys +import com.koalasat.pokey.models.EncryptedStorage import com.vitorpamplona.quartz.encoders.Nip19Bech32 import com.vitorpamplona.quartz.encoders.Nip19Bech32.uriToRoute class HomeViewModel : ViewModel() { - private val _npubInput = MutableLiveData().apply { - value = preferences().getString(PrefKeys.NOSTR_PUBKEY, "").toString() - } + private val _npubInput = MutableLiveData() val npubInput: LiveData get() = _npubInput - private val _serviceStart = MutableLiveData().apply { - value = Pokey.isEnabled.value - } + private val _serviceStart = MutableLiveData() val serviceStart: LiveData get() = _serviceStart - private val _validationResult = MutableLiveData().apply { - value = preferences().getString(PrefKeys.NOSTR_PUBKEY, "")?.isNotEmpty() - } + private val _validationResult = MutableLiveData() val validationResult: LiveData get() = _validationResult + init { + _npubInput.value = EncryptedStorage.pubKey.value + _serviceStart.value = Pokey.isEnabled.value + _validationResult.value = EncryptedStorage.pubKey.value?.isNotEmpty() + EncryptedStorage.pubKey.observeForever { text -> + _npubInput.value = text + } + } + fun updateServiceStart(value: Boolean) { if (value) { Pokey.getInstance().startService() @@ -38,9 +40,7 @@ class HomeViewModel : ViewModel() { _npubInput.value = text validateNpubInput() if (_validationResult.value == true) { - preferences().edit().apply { - putString(PrefKeys.NOSTR_PUBKEY, text) - }.apply() + EncryptedStorage.updatePubKey(text) } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 723667a..d267ef5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,6 +23,7 @@ ksp = "2.0.20-1.0.24" ktlint = "12.1.1" [libraries] +androidx-activity-ktx = { module = "androidx.activity:activity-ktx" } androidx-compiler = { module = "androidx.compose.compiler:compiler", version.ref = "compiler" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } junit = { group = "junit", name = "junit", version.ref = "junit" }