decrypt private bookmark
This commit is contained in:
@@ -83,7 +83,7 @@ object LocalPreferences {
|
|||||||
|
|
||||||
private var _currentAccount: String? = null
|
private var _currentAccount: String? = null
|
||||||
|
|
||||||
private fun currentAccount(): String? {
|
fun currentAccount(): String? {
|
||||||
if (_currentAccount == null) {
|
if (_currentAccount == null) {
|
||||||
_currentAccount = encryptedPreferences().getString(PrefKeys.CURRENT_ACCOUNT, null)
|
_currentAccount = encryptedPreferences().getString(PrefKeys.CURRENT_ACCOUNT, null)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,17 @@ package com.vitorpamplona.amethyst.model
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
import com.vitorpamplona.amethyst.Amethyst
|
import com.vitorpamplona.amethyst.Amethyst
|
||||||
|
import com.vitorpamplona.amethyst.LocalPreferences
|
||||||
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
||||||
import com.vitorpamplona.amethyst.service.relays.Relay
|
import com.vitorpamplona.amethyst.service.relays.Relay
|
||||||
import com.vitorpamplona.amethyst.ui.components.BundledInsert
|
import com.vitorpamplona.amethyst.ui.components.BundledInsert
|
||||||
|
import com.vitorpamplona.amethyst.ui.dal.BookmarkPrivateFeedFilter
|
||||||
import com.vitorpamplona.quartz.encoders.ATag
|
import com.vitorpamplona.quartz.encoders.ATag
|
||||||
import com.vitorpamplona.quartz.encoders.Hex
|
import com.vitorpamplona.quartz.encoders.Hex
|
||||||
import com.vitorpamplona.quartz.encoders.HexKey
|
import com.vitorpamplona.quartz.encoders.HexKey
|
||||||
import com.vitorpamplona.quartz.encoders.HexValidator
|
import com.vitorpamplona.quartz.encoders.HexValidator
|
||||||
import com.vitorpamplona.quartz.encoders.Nip19
|
import com.vitorpamplona.quartz.encoders.Nip19
|
||||||
|
import com.vitorpamplona.quartz.encoders.bechToBytes
|
||||||
import com.vitorpamplona.quartz.encoders.decodePublicKeyAsHexOrNull
|
import com.vitorpamplona.quartz.encoders.decodePublicKeyAsHexOrNull
|
||||||
import com.vitorpamplona.quartz.encoders.toHexKey
|
import com.vitorpamplona.quartz.encoders.toHexKey
|
||||||
import com.vitorpamplona.quartz.events.*
|
import com.vitorpamplona.quartz.events.*
|
||||||
@@ -199,6 +202,14 @@ object LocalCache {
|
|||||||
val user = getOrCreateUser(event.pubKey)
|
val user = getOrCreateUser(event.pubKey)
|
||||||
if (user.latestBookmarkList == null || event.createdAt > user.latestBookmarkList!!.createdAt) {
|
if (user.latestBookmarkList == null || event.createdAt > user.latestBookmarkList!!.createdAt) {
|
||||||
if (event.dTag() == "bookmark") {
|
if (event.dTag() == "bookmark") {
|
||||||
|
val loggedInUser = LocalPreferences.currentAccount()
|
||||||
|
val hexKey = loggedInUser?.bechToBytes()
|
||||||
|
if (hexKey != null) {
|
||||||
|
val pubKey = Hex.encode(hexKey)
|
||||||
|
if (pubKey == event.pubKey) {
|
||||||
|
BookmarkPrivateFeedFilter.content = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
user.updateBookmark(event)
|
user.updateBookmark(event)
|
||||||
}
|
}
|
||||||
// Log.d("MT", "New User Metadata ${oldUser.pubkeyDisplayHex} ${oldUser.toBestDisplayName()}")
|
// Log.d("MT", "New User Metadata ${oldUser.pubkeyDisplayHex} ${oldUser.toBestDisplayName()}")
|
||||||
|
|||||||
@@ -6,4 +6,5 @@ import androidx.activity.result.ActivityResultLauncher
|
|||||||
object IntentUtils {
|
object IntentUtils {
|
||||||
lateinit var activityResultLauncher: ActivityResultLauncher<Intent>
|
lateinit var activityResultLauncher: ActivityResultLauncher<Intent>
|
||||||
lateinit var authActivityResultLauncher: ActivityResultLauncher<Intent>
|
lateinit var authActivityResultLauncher: ActivityResultLauncher<Intent>
|
||||||
|
lateinit var decryptActivityResultLauncher: ActivityResultLauncher<Intent>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import com.vitorpamplona.amethyst.service.notifications.RegisterAccounts
|
|||||||
import com.vitorpamplona.amethyst.service.relays.Client
|
import com.vitorpamplona.amethyst.service.relays.Client
|
||||||
import com.vitorpamplona.amethyst.ui.components.DefaultMutedSetting
|
import com.vitorpamplona.amethyst.ui.components.DefaultMutedSetting
|
||||||
import com.vitorpamplona.amethyst.ui.components.keepPlayingMutex
|
import com.vitorpamplona.amethyst.ui.components.keepPlayingMutex
|
||||||
|
import com.vitorpamplona.amethyst.ui.dal.BookmarkPrivateFeedFilter
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.Route
|
import com.vitorpamplona.amethyst.ui.navigation.Route
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.debugState
|
import com.vitorpamplona.amethyst.ui.navigation.debugState
|
||||||
import com.vitorpamplona.amethyst.ui.note.Nip47
|
import com.vitorpamplona.amethyst.ui.note.Nip47
|
||||||
@@ -110,6 +111,26 @@ class MainActivity : AppCompatActivity() {
|
|||||||
ServiceManager.shouldPauseService = true
|
ServiceManager.shouldPauseService = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IntentUtils.decryptActivityResultLauncher = registerForActivityResult(
|
||||||
|
ActivityResultContracts.StartActivityForResult()
|
||||||
|
) {
|
||||||
|
if (it.resultCode != Activity.RESULT_OK) {
|
||||||
|
GlobalScope.launch(Dispatchers.Main) {
|
||||||
|
Toast.makeText(
|
||||||
|
Amethyst.instance,
|
||||||
|
"Sign request rejected",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
BookmarkPrivateFeedFilter.isActivityRunning = false
|
||||||
|
return@registerForActivityResult
|
||||||
|
}
|
||||||
|
|
||||||
|
val event = it.data?.getStringExtra("signature") ?: ""
|
||||||
|
BookmarkPrivateFeedFilter.content = event
|
||||||
|
BookmarkPrivateFeedFilter.isActivityRunning = false
|
||||||
|
}
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
LocalPreferences.migrateSingleUserPrefs()
|
LocalPreferences.migrateSingleUserPrefs()
|
||||||
|
|||||||
@@ -3,27 +3,57 @@ package com.vitorpamplona.amethyst.ui.dal
|
|||||||
import com.vitorpamplona.amethyst.model.Account
|
import com.vitorpamplona.amethyst.model.Account
|
||||||
import com.vitorpamplona.amethyst.model.LocalCache
|
import com.vitorpamplona.amethyst.model.LocalCache
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
|
import com.vitorpamplona.amethyst.service.IntentUtils
|
||||||
|
import com.vitorpamplona.amethyst.ui.actions.SignerType
|
||||||
|
import com.vitorpamplona.amethyst.ui.actions.openAmber
|
||||||
|
import com.vitorpamplona.quartz.encoders.toHexKey
|
||||||
|
|
||||||
object BookmarkPrivateFeedFilter : FeedFilter<Note>() {
|
object BookmarkPrivateFeedFilter : FeedFilter<Note>() {
|
||||||
lateinit var account: Account
|
lateinit var account: Account
|
||||||
|
var content: String = ""
|
||||||
|
var isActivityRunning: Boolean = false
|
||||||
|
|
||||||
override fun feedKey(): String {
|
override fun feedKey(): String {
|
||||||
return account.userProfile().latestBookmarkList?.id ?: ""
|
return account.userProfile().latestBookmarkList?.id ?: ""
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun feed(): List<Note> {
|
override fun feed(): List<Note> {
|
||||||
val privKey = account.keyPair.privKey ?: return emptyList()
|
|
||||||
|
|
||||||
val bookmarks = account.userProfile().latestBookmarkList
|
val bookmarks = account.userProfile().latestBookmarkList
|
||||||
|
|
||||||
val notes = bookmarks?.privateTaggedEvents(privKey)
|
if (account.loginWithAmber) {
|
||||||
?.mapNotNull { LocalCache.checkGetOrCreateNote(it) } ?: emptyList()
|
if (content.isBlank()) {
|
||||||
|
isActivityRunning = true
|
||||||
|
openAmber(
|
||||||
|
bookmarks?.content ?: "",
|
||||||
|
SignerType.NIP04_DECRYPT,
|
||||||
|
IntentUtils.decryptActivityResultLauncher,
|
||||||
|
account.keyPair.pubKey.toHexKey()
|
||||||
|
)
|
||||||
|
while (isActivityRunning) {
|
||||||
|
Thread.sleep(250)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val addresses = bookmarks?.privateTaggedAddresses(privKey)
|
val notes = bookmarks?.privateTaggedEvents(content)
|
||||||
?.map { LocalCache.getOrCreateAddressableNote(it) } ?: emptyList()
|
?.mapNotNull { LocalCache.checkGetOrCreateNote(it) } ?: emptyList()
|
||||||
|
val addresses = bookmarks?.privateTaggedAddresses(content)
|
||||||
|
?.map { LocalCache.getOrCreateAddressableNote(it) } ?: emptyList()
|
||||||
|
|
||||||
return notes.plus(addresses).toSet()
|
return notes.plus(addresses).toSet()
|
||||||
.sortedWith(compareBy({ it.createdAt() }, { it.idHex }))
|
.sortedWith(compareBy({ it.createdAt() }, { it.idHex }))
|
||||||
.reversed()
|
.reversed()
|
||||||
|
} else {
|
||||||
|
val privKey = account.keyPair.privKey ?: return emptyList()
|
||||||
|
|
||||||
|
val notes = bookmarks?.privateTaggedEvents(privKey)
|
||||||
|
?.mapNotNull { LocalCache.checkGetOrCreateNote(it) } ?: emptyList()
|
||||||
|
|
||||||
|
val addresses = bookmarks?.privateTaggedAddresses(privKey)
|
||||||
|
?.map { LocalCache.getOrCreateAddressableNote(it) } ?: emptyList()
|
||||||
|
|
||||||
|
return notes.plus(addresses).toSet()
|
||||||
|
.sortedWith(compareBy({ it.createdAt() }, { it.idHex }))
|
||||||
|
.reversed()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import androidx.compose.material.Tab
|
|||||||
import androidx.compose.material.TabRow
|
import androidx.compose.material.TabRow
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.livedata.observeAsState
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
@@ -91,5 +92,11 @@ fun BookmarkListScreen(accountViewModel: AccountViewModel, nav: (String) -> Unit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DisposableEffect(Unit) {
|
||||||
|
onDispose {
|
||||||
|
BookmarkPrivateFeedFilter.content = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,20 @@ abstract class GeneralListEvent(
|
|||||||
return privateTagsCache
|
return privateTagsCache
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun privateTags(content: String): List<List<String>>? {
|
||||||
|
if (privateTagsCache != null) {
|
||||||
|
return privateTagsCache
|
||||||
|
}
|
||||||
|
|
||||||
|
privateTagsCache = try {
|
||||||
|
content.let { mapper.readValue<List<List<String>>>(it) }
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
Log.w("GeneralList", "Error parsing the JSON ${e.message}")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
return privateTagsCache
|
||||||
|
}
|
||||||
|
|
||||||
fun privateTagsOrEmpty(privKey: ByteArray): List<List<String>> {
|
fun privateTagsOrEmpty(privKey: ByteArray): List<List<String>> {
|
||||||
return privateTags(privKey) ?: emptyList()
|
return privateTags(privKey) ?: emptyList()
|
||||||
}
|
}
|
||||||
@@ -61,6 +75,8 @@ abstract class GeneralListEvent(
|
|||||||
fun privateHashtags(privKey: ByteArray) = privateTags(privKey)?.filter { it.size > 1 && it[0] == "t" }?.map { it[1] }
|
fun privateHashtags(privKey: ByteArray) = privateTags(privKey)?.filter { it.size > 1 && it[0] == "t" }?.map { it[1] }
|
||||||
fun privateGeohashes(privKey: ByteArray) = privateTags(privKey)?.filter { it.size > 1 && it[0] == "g" }?.map { it[1] }
|
fun privateGeohashes(privKey: ByteArray) = privateTags(privKey)?.filter { it.size > 1 && it[0] == "g" }?.map { it[1] }
|
||||||
fun privateTaggedEvents(privKey: ByteArray) = privateTags(privKey)?.filter { it.size > 1 && it[0] == "e" }?.map { it[1] }
|
fun privateTaggedEvents(privKey: ByteArray) = privateTags(privKey)?.filter { it.size > 1 && it[0] == "e" }?.map { it[1] }
|
||||||
|
fun privateTaggedEvents(content: String) = privateTags(content)?.filter { it.size > 1 && it[0] == "e" }?.map { it[1] }
|
||||||
|
|
||||||
fun privateTaggedAddresses(privKey: ByteArray) = privateTags(privKey)?.filter { it.firstOrNull() == "a" }?.mapNotNull {
|
fun privateTaggedAddresses(privKey: ByteArray) = privateTags(privKey)?.filter { it.firstOrNull() == "a" }?.mapNotNull {
|
||||||
val aTagValue = it.getOrNull(1)
|
val aTagValue = it.getOrNull(1)
|
||||||
val relay = it.getOrNull(2)
|
val relay = it.getOrNull(2)
|
||||||
@@ -68,6 +84,13 @@ abstract class GeneralListEvent(
|
|||||||
if (aTagValue != null) ATag.parse(aTagValue, relay) else null
|
if (aTagValue != null) ATag.parse(aTagValue, relay) else null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun privateTaggedAddresses(content: String) = privateTags(content)?.filter { it.firstOrNull() == "a" }?.mapNotNull {
|
||||||
|
val aTagValue = it.getOrNull(1)
|
||||||
|
val relay = it.getOrNull(2)
|
||||||
|
|
||||||
|
if (aTagValue != null) ATag.parse(aTagValue, relay) else null
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun createPrivateTags(
|
fun createPrivateTags(
|
||||||
privEvents: List<String>? = null,
|
privEvents: List<String>? = null,
|
||||||
|
|||||||
Reference in New Issue
Block a user