Skip to content

Commit

Permalink
Merge pull request #19 from KoalaSat/nip-42
Browse files Browse the repository at this point in the history
NIP-42 Auth to Relays
  • Loading branch information
KoalaSat authored Oct 28, 2024
2 parents 88d172c + 2463be1 commit 8db3a0a
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 36 deletions.
2 changes: 2 additions & 0 deletions app/src/main/java/com/koalasat/pokey/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ 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.koalasat.pokey.models.ExternalSigner

class MainActivity : AppCompatActivity() {
private val requestCodePostNotifications: Int = 1
Expand All @@ -24,6 +25,7 @@ class MainActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)

EncryptedStorage.init(this)
ExternalSigner.init(this)

binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
Expand Down
25 changes: 20 additions & 5 deletions app/src/main/java/com/koalasat/pokey/Pokey.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ import android.content.Intent
import android.content.SharedPreferences
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.koalasat.pokey.models.EncryptedStorage
import com.koalasat.pokey.service.NotificationsService
import com.vitorpamplona.ammolite.relays.Client
import com.vitorpamplona.ammolite.relays.RelayPool
import com.vitorpamplona.quartz.encoders.Nip19Bech32
import com.vitorpamplona.quartz.encoders.Nip19Bech32.uriToRoute
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
Expand Down Expand Up @@ -50,6 +53,18 @@ class Pokey : Application() {

fun contentResolverFn(): ContentResolver = contentResolver

fun getHexKey(): String {
val pubKey = EncryptedStorage.pubKey.value
var hexKey = ""
val parseReturn = uriToRoute(pubKey)
when (val parsed = parseReturn?.entity) {
is Nip19Bech32.NPub -> {
hexKey = parsed.hex
}
}
return hexKey
}

companion object {
private val _isEnabled = MutableLiveData(false)
val isEnabled: LiveData<Boolean> get() = _isEnabled
Expand All @@ -66,17 +81,17 @@ class Pokey : Application() {
_isEnabled.value = value
}

fun isForegroundServiceEnabled(context: Context): Boolean {
val sharedPreferences: SharedPreferences = context.getSharedPreferences("PokeyPreferences", Context.MODE_PRIVATE)
return sharedPreferences.getBoolean("foreground_service_enabled", false)
}

private fun saveForegroundServicePreference(context: Context, value: Boolean) {
val sharedPreferences: SharedPreferences = context.getSharedPreferences("PokeyPreferences", Context.MODE_PRIVATE)
val editor = sharedPreferences.edit()
editor.putBoolean("foreground_service_enabled", value)
editor.apply()
updateIsEnabled(value)
}

fun isForegroundServiceEnabled(context: Context): Boolean {
val sharedPreferences: SharedPreferences = context.getSharedPreferences("PokeyPreferences", Context.MODE_PRIVATE)
return sharedPreferences.getBoolean("foreground_service_enabled", false)
}
}
}
42 changes: 36 additions & 6 deletions app/src/main/java/com/koalasat/pokey/models/ExternalSigner.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,26 @@ import android.util.Log
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.Fragment
import androidx.appcompat.app.AppCompatActivity
import com.koalasat.pokey.Pokey
import com.koalasat.pokey.R
import com.vitorpamplona.quartz.encoders.toHexKey
import com.vitorpamplona.quartz.events.Event
import com.vitorpamplona.quartz.signers.ExternalSignerLauncher
import com.vitorpamplona.quartz.signers.SignerType
import com.vitorpamplona.quartz.utils.TimeUtils
import java.util.UUID
import kotlin.coroutines.cancellation.CancellationException

class ExternalSigner(fragment: Fragment) {
private var nostrSignerLauncher: ActivityResultLauncher<Intent>
object ExternalSigner {
private lateinit var nostrSignerLauncher: ActivityResultLauncher<Intent>
private var externalSignerLauncher: ExternalSignerLauncher = ExternalSignerLauncher("", signerPackageName = "")

init {
nostrSignerLauncher = fragment.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
fun init(activity: AppCompatActivity) {
nostrSignerLauncher = activity.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode != Activity.RESULT_OK) {
Log.e("Pokey", "ExternalSigner result error: ${result.resultCode}")
Toast.makeText(fragment.context, fragment.getString(R.string.amber_not_found), Toast.LENGTH_SHORT).show()
Toast.makeText(activity, activity.getString(R.string.amber_not_found), Toast.LENGTH_SHORT).show()
} else {
result.data?.let { externalSignerLauncher.newResult(it) }
}
Expand Down Expand Up @@ -52,4 +55,31 @@ class ExternalSigner(fragment: Fragment) {
if (split.first().isNotEmpty()) EncryptedStorage.updatePubKey(pubkey)
}
}

fun auth(relayUrl: String, challenge: String, onReady: (String) -> Unit) {
val pubKey = Pokey.getInstance().getHexKey()
val createdAt = TimeUtils.now()
val kind = 22242
val content = ""
val tags =
arrayOf(
arrayOf("relay", relayUrl),
arrayOf("challenge", challenge),
)
val id = Event.generateId(pubKey, createdAt, kind, tags, content).toHexKey()
val event =
Event(
id = id,
pubKey = pubKey,
createdAt = createdAt,
kind = kind,
tags = tags,
content = content,
sig = "",
)
externalSignerLauncher.openSigner(
event,
onReady,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ import android.os.IBinder
import android.util.Log
import androidx.core.app.NotificationCompat
import com.koalasat.pokey.Connectivity
import com.koalasat.pokey.Pokey
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
import com.koalasat.pokey.models.ExternalSigner
import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES
import com.vitorpamplona.ammolite.relays.Client
import com.vitorpamplona.ammolite.relays.EVENT_FINDER_TYPES
Expand All @@ -28,8 +30,6 @@ import com.vitorpamplona.ammolite.relays.filters.EOSETime
import com.vitorpamplona.ammolite.relays.filters.SincePerRelayFilter
import com.vitorpamplona.quartz.encoders.Hex
import com.vitorpamplona.quartz.encoders.LnInvoiceUtil
import com.vitorpamplona.quartz.encoders.Nip19Bech32
import com.vitorpamplona.quartz.encoders.Nip19Bech32.uriToRoute
import com.vitorpamplona.quartz.encoders.toNote
import com.vitorpamplona.quartz.encoders.toNpub
import com.vitorpamplona.quartz.events.Event
Expand Down Expand Up @@ -67,7 +67,10 @@ class NotificationsService : Service() {
private val clientListener =
object : Client.Listener {
override fun onAuth(relay: Relay, challenge: String) {
Log.d("Pokey", "Relay on Auth: ${relay.url}")
Log.d("Pokey", "Relay on Auth: ${relay.url} : $challenge")
ExternalSigner.auth(relay.url, challenge) { result ->
Log.d("Pokey", "Relay on Auth response: ${relay.url} : $result")
}
}

override fun onSend(relay: Relay, msg: String, success: Boolean) {
Expand Down Expand Up @@ -161,6 +164,7 @@ class NotificationsService : Service() {
val connectivityManager =
(getSystemService(ConnectivityManager::class.java) as ConnectivityManager)
connectivityManager.registerDefaultNetworkCallback(networkCallback)

super.onCreate()
}

Expand All @@ -187,20 +191,20 @@ class NotificationsService : Service() {
(getSystemService(ConnectivityManager::class.java) as ConnectivityManager)
connectivityManager.unregisterNetworkCallback(networkCallback)
} catch (e: Exception) {
Log.d("connectivityManager", "Failed to unregisterNetworkCallback", e)
Log.d("Pokey", "Failed to unregisterNetworkCallback", e)
}

super.onDestroy()
}

private fun startSubscription() {
val hexKey = getHexKey()
val hexKey = Pokey.getInstance().getHexKey()
if (hexKey.isEmpty()) return

CoroutineScope(Dispatchers.IO).launch {
if (!Client.isSubscribed(clientListener)) Client.subscribe(clientListener)

val dao = AppDatabase.getDatabase(this@NotificationsService, getHexKey()).applicationDao()
val dao = AppDatabase.getDatabase(this@NotificationsService, hexKey).applicationDao()
var latestNotification = dao.getLatestNotification()
if (latestNotification == null) latestNotification = Instant.now().toEpochMilli() / 1000

Expand Down Expand Up @@ -299,7 +303,7 @@ class NotificationsService : Service() {

private fun manageInboxRelays(event: Event) {
CoroutineScope(Dispatchers.IO).launch {
val dao = AppDatabase.getDatabase(this@NotificationsService, getHexKey()).applicationDao()
val dao = AppDatabase.getDatabase(this@NotificationsService, Pokey.getInstance().getHexKey()).applicationDao()
val lastCreatedRelayAt = dao.getLatestRelaysByKind(event.kind)

if (lastCreatedRelayAt == null || lastCreatedRelayAt < event.createdAt) {
Expand All @@ -318,11 +322,11 @@ class NotificationsService : Service() {
}

private fun createNoteNotification(event: Event) {
val hexKey = getHexKey()
val hexKey = Pokey.getInstance().getHexKey()
if (event.pubKey == hexKey || !event.taggedUsers().contains(hexKey)) return

CoroutineScope(Dispatchers.IO).launch {
val dao = AppDatabase.getDatabase(this@NotificationsService, getHexKey()).applicationDao()
val dao = AppDatabase.getDatabase(this@NotificationsService, hexKey).applicationDao()
val existsEvent = dao.existsNotification(event.id)
if (existsEvent > 0) return@launch

Expand Down Expand Up @@ -431,25 +435,14 @@ class NotificationsService : Service() {
notificationManager.notify(event.hashCode(), builder.build())
}

private fun getHexKey(): String {
val pubKey = EncryptedStorage.pubKey.value
var hexKey = ""
val parseReturn = uriToRoute(pubKey)
when (val parsed = parseReturn?.entity) {
is Nip19Bech32.NPub -> {
hexKey = parsed.hex
}
}
return hexKey
}

private fun connectRelays() {
RelayPool.unloadRelays()
val dao = AppDatabase.getDatabase(this@NotificationsService, getHexKey()).applicationDao()
val dao = AppDatabase.getDatabase(this@NotificationsService, Pokey.getInstance().getHexKey()).applicationDao()
var relays = dao.getRelays()
if (relays.isEmpty()) {
relays = defaultRelayUrls.map { RelayEntity(id = 0, url = it, kind = 0, createdAt = 0) }
}

relays.forEach {
Client.sendFilterOnlyIfDisconnected()
RelayPool.addRelay(
Expand Down
4 changes: 1 addition & 3 deletions app/src/main/java/com/koalasat/pokey/ui/home/HomeFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ class HomeFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

val externalSigner = ExternalSigner(this)

binding.npubInput.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}

Expand Down Expand Up @@ -79,7 +77,7 @@ class HomeFragment : Fragment() {
}

binding.amber.setOnClickListener {
externalSigner.savePubKey()
ExternalSigner.savePubKey()
}
}

Expand Down

0 comments on commit 8db3a0a

Please sign in to comment.