diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index a894dfe6e..295284733 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -169,8 +169,7 @@ class Account( val event = ContactListEvent.updateRelayList( earlierVersion = contactList, relayUse = relays, - pubKey = keyPair.pubKey.toHexKey(), - privateKey = keyPair.privKey + keyPair = keyPair ) if (!signEvent) { @@ -188,8 +187,7 @@ class Account( followCommunities = listOf(), followEvents = DefaultChannels.toList(), relayUse = relays, - privateKey = keyPair.privKey!!, - publicKey = if (!signEvent) keyPair.pubKey else null + keyPair = keyPair ) if (!signEvent) { @@ -511,11 +509,7 @@ class Account( if (followingCommunities.isNotEmpty()) { followingCommunities.forEach { ATag.parse(it, null)?.let { - returningContactList = if (keyPair.privKey == null) { - ContactListEvent.followAddressableEvent(returningContactList, it, keyPair.pubKey.toHexKey()) - } else { - ContactListEvent.followAddressableEvent(returningContactList, it, keyPair.pubKey.toHexKey(), keyPair.privKey) - } + returningContactList = ContactListEvent.followAddressableEvent(returningContactList, it, keyPair) } } followingCommunities = emptySet() @@ -523,11 +517,7 @@ class Account( if (followingChannels.isNotEmpty()) { followingChannels.forEach { - returningContactList = if (keyPair.privKey == null) { - ContactListEvent.followEvent(returningContactList, it, keyPair.pubKey.toHexKey()) - } else { - ContactListEvent.followEvent(returningContactList, it, keyPair.pubKey.toHexKey(), keyPair.privKey) - } + returningContactList = ContactListEvent.followEvent(returningContactList, it, keyPair) } followingChannels = emptySet() } @@ -541,11 +531,7 @@ class Account( val contactList = migrateCommunitiesAndChannelsIfNeeded(userProfile().latestContactList) val event = if (contactList != null) { - if (signEvent) { - ContactListEvent.followUser(contactList, user.pubkeyHex, keyPair.privKey!!) - } else { - ContactListEvent.followUser(contactList, user.pubkeyHex, keyPair.pubKey.toHexKey()) - } + ContactListEvent.followUser(contactList, user.pubkeyHex, keyPair) } else { ContactListEvent.createFromScratch( followUsers = listOf(Contact(user.pubkeyHex, null)), @@ -554,8 +540,7 @@ class Account( followCommunities = emptyList(), followEvents = DefaultChannels.toList(), relayUse = Constants.defaultRelays.associate { it.url to ContactListEvent.ReadWrite(it.read, it.write) }, - privateKey = keyPair.privKey, - publicKey = if (signEvent) null else keyPair.pubKey + keyPair = keyPair ) } @@ -574,7 +559,7 @@ class Account( val contactList = migrateCommunitiesAndChannelsIfNeeded(userProfile().latestContactList) val event = if (contactList != null) { - ContactListEvent.followEvent(contactList, channel.idHex, keyPair.pubKey.toHexKey(), keyPair.privKey) + ContactListEvent.followEvent(contactList, channel.idHex, keyPair) } else { ContactListEvent.createFromScratch( followUsers = emptyList(), @@ -583,8 +568,7 @@ class Account( followCommunities = emptyList(), followEvents = DefaultChannels.toList().plus(channel.idHex), relayUse = Constants.defaultRelays.associate { it.url to ContactListEvent.ReadWrite(it.read, it.write) }, - publicKey = if (!signEvent) keyPair.pubKey else null, - privateKey = keyPair.privKey + keyPair = keyPair ) } @@ -603,7 +587,7 @@ class Account( val contactList = migrateCommunitiesAndChannelsIfNeeded(userProfile().latestContactList) val event = if (contactList != null) { - ContactListEvent.followAddressableEvent(contactList, community.address, keyPair.pubKey.toHexKey(), keyPair.privKey) + ContactListEvent.followAddressableEvent(contactList, community.address, keyPair) } else { val relays = Constants.defaultRelays.associate { it.url to ContactListEvent.ReadWrite(it.read, it.write) } ContactListEvent.createFromScratch( @@ -613,8 +597,7 @@ class Account( followCommunities = listOf(community.address), followEvents = DefaultChannels.toList(), relayUse = relays, - publicKey = if (!signEvent) keyPair.pubKey else null, - privateKey = keyPair.privKey + keyPair = keyPair ) } @@ -633,19 +616,11 @@ class Account( val contactList = migrateCommunitiesAndChannelsIfNeeded(userProfile().latestContactList) val event = if (contactList != null) { - if (signEvent) { - ContactListEvent.followHashtag( - contactList, - tag, - keyPair.privKey!! - ) - } else { - ContactListEvent.followHashtag( - contactList, - tag, - keyPair.pubKey.toHexKey() - ) - } + ContactListEvent.followHashtag( + contactList, + tag, + keyPair + ) } else { ContactListEvent.createFromScratch( followUsers = emptyList(), @@ -654,8 +629,7 @@ class Account( followCommunities = emptyList(), followEvents = DefaultChannels.toList(), relayUse = Constants.defaultRelays.associate { it.url to ContactListEvent.ReadWrite(it.read, it.write) }, - privateKey = keyPair.privKey, - publicKey = if (signEvent) null else keyPair.pubKey + keyPair = keyPair ) } @@ -668,8 +642,8 @@ class Account( return null } - fun followGeohash(geohash: String) { - if (!isWriteable()) return + fun followGeohash(geohash: String, signEvent: Boolean): ContactListEvent? { + if (!isWriteable() && signEvent) return null val contactList = migrateCommunitiesAndChannelsIfNeeded(userProfile().latestContactList) @@ -677,7 +651,7 @@ class Account( ContactListEvent.followGeohash( contactList, geohash, - keyPair.privKey!! + keyPair ) } else { ContactListEvent.createFromScratch( @@ -687,12 +661,17 @@ class Account( followCommunities = emptyList(), followEvents = DefaultChannels.toList(), relayUse = Constants.defaultRelays.associate { it.url to ContactListEvent.ReadWrite(it.read, it.write) }, - privateKey = keyPair.privKey!! + keyPair = keyPair ) } + if (!signEvent) { + return event + } + Client.send(event) LocalCache.consume(event) + return null } fun unfollow(user: User, signEvent: Boolean = true): ContactListEvent? { @@ -701,20 +680,16 @@ class Account( val contactList = migrateCommunitiesAndChannelsIfNeeded(userProfile().latestContactList) if (contactList != null && contactList.tags.isNotEmpty()) { - if (!signEvent) { - return ContactListEvent.unfollowUser( - contactList, - user.pubkeyHex, - keyPair.pubKey.toHexKey() - ) - } - val event = ContactListEvent.unfollowUser( contactList, user.pubkeyHex, - keyPair.privKey!! + keyPair ) + if (!signEvent) { + return event + } + Client.send(event) LocalCache.consume(event) } @@ -728,20 +703,16 @@ class Account( val contactList = migrateCommunitiesAndChannelsIfNeeded(userProfile().latestContactList) if (contactList != null && contactList.tags.isNotEmpty()) { - if (!signEvent) { - return ContactListEvent.unfollowHashtag( - contactList, - tag, - keyPair.pubKey.toHexKey() - ) - } - val event = ContactListEvent.unfollowHashtag( contactList, tag, - keyPair.privKey!! + keyPair ) + if (!signEvent) { + return event + } + Client.send(event) LocalCache.consume(event) @@ -751,8 +722,8 @@ class Account( return null } - fun unfollowGeohash(geohash: String) { - if (!isWriteable()) return + fun unfollowGeohash(geohash: String, signEvent: Boolean): ContactListEvent? { + if (!isWriteable() && signEvent) return null val contactList = migrateCommunitiesAndChannelsIfNeeded(userProfile().latestContactList) @@ -760,12 +731,18 @@ class Account( val event = ContactListEvent.unfollowGeohash( contactList, geohash, - keyPair.privKey!! + keyPair ) + if (!signEvent) { + return event + } + Client.send(event) LocalCache.consume(event) + return null } + return null } fun unfollow(channel: Channel, signEvent: Boolean): ContactListEvent? { @@ -777,8 +754,7 @@ class Account( val event = ContactListEvent.unfollowEvent( contactList, channel.idHex, - keyPair.pubKey.toHexKey(), - keyPair.privKey + keyPair ) if (!signEvent) { @@ -800,8 +776,7 @@ class Account( val event = ContactListEvent.unfollowAddressableEvent( contactList, community.address, - keyPair.pubKey.toHexKey(), - keyPair.privKey + keyPair ) if (!signEvent) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewRelayListView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewRelayListView.kt index 2863eca91..037431a32 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewRelayListView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewRelayListView.kt @@ -59,7 +59,6 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.RelayInformation import com.vitorpamplona.amethyst.model.RelaySetupInfo -import com.vitorpamplona.amethyst.service.PackageUtils import com.vitorpamplona.amethyst.service.relays.Client import com.vitorpamplona.amethyst.service.relays.Constants.defaultRelays import com.vitorpamplona.amethyst.service.relays.FeedType @@ -145,7 +144,7 @@ fun NewRelayListView(onClose: () -> Unit, accountViewModel: AccountViewModel, re PostButton( onPost = { - if (PackageUtils.isAmberInstalled(context)) { + if (accountViewModel.loggedInWithAmber()) { event = postViewModel.create(false) } else { postViewModel.create(true) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapNoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapNoteCompose.kt index 00cd317be..29f7b3e0a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapNoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapNoteCompose.kt @@ -29,7 +29,6 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User -import com.vitorpamplona.amethyst.service.PackageUtils import com.vitorpamplona.amethyst.service.relays.Client import com.vitorpamplona.amethyst.ui.actions.SignerDialog import com.vitorpamplona.amethyst.ui.screen.ZapReqResponse @@ -233,7 +232,7 @@ fun ShowFollowingOrUnfollowingButton( if (isFollowing) { UnfollowButton { if (!accountViewModel.isWriteable()) { - if (PackageUtils.isAmberInstalled(context)) { + if (accountViewModel.loggedInWithAmber()) { event = accountViewModel.account.unfollow(baseAuthor, false) } else { scope.launch { @@ -255,7 +254,7 @@ fun ShowFollowingOrUnfollowingButton( } else { FollowButton { if (!accountViewModel.isWriteable()) { - if (PackageUtils.isAmberInstalled(context)) { + if (accountViewModel.loggedInWithAmber()) { event = accountViewModel.account.follow(baseAuthor, false) } else { scope.launch { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index 7646f4876..d6f0901d5 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -84,6 +84,10 @@ class AccountViewModel(val account: Account) : ViewModel() { return account.isWriteable() } + fun loggedInWithAmber(): Boolean { + return account.loginWithAmber + } + fun userProfile(): User { return account.userProfile() } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt index 8cd81a23a..1f9647184 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChannelScreen.kt @@ -86,7 +86,6 @@ import com.vitorpamplona.amethyst.model.PublicChatChannel import com.vitorpamplona.amethyst.model.ServersAvailable import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.service.NostrChannelDataSource -import com.vitorpamplona.amethyst.service.PackageUtils import com.vitorpamplona.amethyst.service.relays.Client import com.vitorpamplona.amethyst.ui.actions.NewChannelView import com.vitorpamplona.amethyst.ui.actions.NewMessageTagger @@ -1131,7 +1130,7 @@ fun JoinChatButton(accountViewModel: AccountViewModel, channel: Channel, nav: (S modifier = Modifier.padding(horizontal = 3.dp), onClick = { scope.launch(Dispatchers.IO) { - event = accountViewModel.account.follow(channel, !PackageUtils.isAmberInstalled(context)) + event = accountViewModel.account.follow(channel, !accountViewModel.loggedInWithAmber()) } }, shape = ButtonBorder, @@ -1171,7 +1170,7 @@ fun LeaveChatButton(accountViewModel: AccountViewModel, channel: Channel, nav: ( modifier = Modifier.padding(horizontal = 3.dp), onClick = { scope.launch(Dispatchers.IO) { - event = accountViewModel.account.unfollow(channel, !PackageUtils.isAmberInstalled(context)) + event = accountViewModel.account.unfollow(channel, !accountViewModel.loggedInWithAmber()) } }, shape = ButtonBorder, @@ -1211,7 +1210,7 @@ fun JoinCommunityButton(accountViewModel: AccountViewModel, note: AddressableNot modifier = Modifier.padding(horizontal = 3.dp), onClick = { scope.launch(Dispatchers.IO) { - event = accountViewModel.account.follow(note, !PackageUtils.isAmberInstalled(context)) + event = accountViewModel.account.follow(note, !accountViewModel.loggedInWithAmber()) } }, shape = ButtonBorder, @@ -1251,7 +1250,7 @@ fun LeaveCommunityButton(accountViewModel: AccountViewModel, note: AddressableNo modifier = Modifier.padding(horizontal = 3.dp), onClick = { scope.launch(Dispatchers.IO) { - event = accountViewModel.account.unfollow(note, !PackageUtils.isAmberInstalled(context)) + event = accountViewModel.account.unfollow(note, !accountViewModel.loggedInWithAmber()) } }, shape = ButtonBorder, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/GeoHashScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/GeoHashScreen.kt index 8d0db4e3c..f2fd180cf 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/GeoHashScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/GeoHashScreen.kt @@ -31,11 +31,15 @@ import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.viewmodel.compose.viewModel import com.fonfon.kgeohash.toGeoHash import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.service.NostrGeohashDataSource import com.vitorpamplona.amethyst.service.ReverseGeoLocationUtil +import com.vitorpamplona.amethyst.service.relays.Client +import com.vitorpamplona.amethyst.ui.actions.SignerDialog import com.vitorpamplona.amethyst.ui.screen.NostrGeoHashFeedViewModel import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView import com.vitorpamplona.amethyst.ui.theme.StdPadding +import com.vitorpamplona.quartz.events.Event import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -167,40 +171,65 @@ fun GeoHashActionOptions( userState?.user?.isFollowingGeohashCached(tag) ?: false } } + var event by remember { mutableStateOf(null) } + if (event != null) { + SignerDialog( + onClose = { + event = null + }, + onPost = { + scope.launch(Dispatchers.IO) { + val signedEvent = Event.fromJson(it) + Client.send(signedEvent) + LocalCache.verifyAndConsume(signedEvent, null) + event = null + } + }, + data = event!!.toJson() + ) + } if (isFollowingTag) { UnfollowButton { if (!accountViewModel.isWriteable()) { - scope.launch { - Toast - .makeText( - context, - context.getString(R.string.login_with_a_private_key_to_be_able_to_unfollow), - Toast.LENGTH_SHORT - ) - .show() + if (accountViewModel.loggedInWithAmber()) { + event = accountViewModel.account.unfollowGeohash(tag, false) + } else { + scope.launch { + Toast + .makeText( + context, + context.getString(R.string.login_with_a_private_key_to_be_able_to_unfollow), + Toast.LENGTH_SHORT + ) + .show() + } } } else { scope.launch(Dispatchers.IO) { - accountViewModel.account.unfollowGeohash(tag) + accountViewModel.account.unfollowGeohash(tag, true) } } } } else { FollowButton { if (!accountViewModel.isWriteable()) { - scope.launch { - Toast - .makeText( - context, - context.getString(R.string.login_with_a_private_key_to_be_able_to_follow), - Toast.LENGTH_SHORT - ) - .show() + if (accountViewModel.loggedInWithAmber()) { + event = accountViewModel.account.followGeohash(tag, false) + } else { + scope.launch { + Toast + .makeText( + context, + context.getString(R.string.login_with_a_private_key_to_be_able_to_follow), + Toast.LENGTH_SHORT + ) + .show() + } } } else { scope.launch(Dispatchers.IO) { - accountViewModel.account.followGeohash(tag) + accountViewModel.account.followGeohash(tag, true) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HashtagScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HashtagScreen.kt index a199407d2..c8d0fe746 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HashtagScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/HashtagScreen.kt @@ -32,7 +32,6 @@ import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.service.NostrHashtagDataSource -import com.vitorpamplona.amethyst.service.PackageUtils import com.vitorpamplona.amethyst.service.relays.Client import com.vitorpamplona.amethyst.ui.actions.SignerDialog import com.vitorpamplona.amethyst.ui.screen.NostrHashtagFeedViewModel @@ -172,7 +171,7 @@ fun HashtagActionOptions( if (isFollowingTag) { UnfollowButton { if (!accountViewModel.isWriteable()) { - if (PackageUtils.isAmberInstalled(context)) { + if (accountViewModel.loggedInWithAmber()) { event = accountViewModel.account.unfollowHashtag(tag, false) } else { scope.launch { @@ -194,7 +193,7 @@ fun HashtagActionOptions( } else { FollowButton { if (!accountViewModel.isWriteable()) { - if (PackageUtils.isAmberInstalled(context)) { + if (accountViewModel.loggedInWithAmber()) { event = accountViewModel.account.followHashtag(tag, false) } else { scope.launch { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt index bcd4af30b..604d4c1b7 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt @@ -791,7 +791,7 @@ private fun DisplayFollowUnfollowButton( if (isUserFollowingLoggedIn) { FollowButton(R.string.follow_back) { if (!accountViewModel.isWriteable()) { - if (PackageUtils.isAmberInstalled(context)) { + if (accountViewModel.loggedInWithAmber()) { event = accountViewModel.account.follow(baseUser, false) } else { scope.launch { @@ -813,7 +813,7 @@ private fun DisplayFollowUnfollowButton( } else { FollowButton(R.string.follow) { if (!accountViewModel.isWriteable()) { - if (PackageUtils.isAmberInstalled(context)) { + if (accountViewModel.loggedInWithAmber()) { event = accountViewModel.account.follow(baseUser, false) } else { scope.launch { diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/ContactListEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/ContactListEvent.kt index 3563650af..895977bd1 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/ContactListEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/ContactListEvent.kt @@ -7,6 +7,7 @@ import com.fasterxml.jackson.module.kotlin.readValue import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.encoders.toHexKey import com.vitorpamplona.quartz.crypto.CryptoUtils +import com.vitorpamplona.quartz.crypto.KeyPair import com.vitorpamplona.quartz.encoders.ATag import com.vitorpamplona.quartz.encoders.HexKey import com.vitorpamplona.quartz.encoders.decodePublicKey @@ -98,9 +99,8 @@ class ContactListEvent( followCommunities: List, followEvents: List, relayUse: Map?, - privateKey: ByteArray?, - createdAt: Long = TimeUtils.now(), - publicKey: ByteArray? = null + keyPair: KeyPair, + createdAt: Long = TimeUtils.now() ): ContactListEvent { val content = if (relayUse != null) { mapper.writeValueAsString(relayUse) @@ -128,268 +128,149 @@ class ContactListEvent( listOf("g", it) } - if (publicKey == null) { - return create( - content = content, - tags = tags, - privateKey = privateKey!!, - createdAt = createdAt - ) - } return create( content = content, tags = tags, - pubKey = publicKey.toHexKey(), + keyPair = keyPair, createdAt = createdAt ) } - fun followUser(earlierVersion: ContactListEvent, pubKeyHex: String, pubKey: HexKey, createdAt: Long = TimeUtils.now()): ContactListEvent { + fun followUser(earlierVersion: ContactListEvent, pubKeyHex: String, keyPair: KeyPair, createdAt: Long = TimeUtils.now()): ContactListEvent { if (earlierVersion.isTaggedUser(pubKeyHex)) return earlierVersion return create( content = earlierVersion.content, tags = earlierVersion.tags.plus(element = listOf("p", pubKeyHex)), - pubKey = pubKey, + keyPair = keyPair, createdAt = createdAt ) } - fun followUser(earlierVersion: ContactListEvent, pubKeyHex: String, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): ContactListEvent { - if (earlierVersion.isTaggedUser(pubKeyHex)) return earlierVersion - - return create( - content = earlierVersion.content, - tags = earlierVersion.tags.plus(element = listOf("p", pubKeyHex)), - privateKey = privateKey, - createdAt = createdAt - ) - } - - fun unfollowUser(earlierVersion: ContactListEvent, pubKeyHex: String, pubKey: HexKey, createdAt: Long = TimeUtils.now()): ContactListEvent { + fun unfollowUser(earlierVersion: ContactListEvent, pubKeyHex: String, keyPair: KeyPair, createdAt: Long = TimeUtils.now()): ContactListEvent { if (!earlierVersion.isTaggedUser(pubKeyHex)) return earlierVersion return create( content = earlierVersion.content, tags = earlierVersion.tags.filter { it.size > 1 && it[1] != pubKeyHex }, - pubKey = pubKey, + keyPair = keyPair, createdAt = createdAt ) } - fun unfollowUser(earlierVersion: ContactListEvent, pubKeyHex: String, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): ContactListEvent { - if (!earlierVersion.isTaggedUser(pubKeyHex)) return earlierVersion - - return create( - content = earlierVersion.content, - tags = earlierVersion.tags.filter { it.size > 1 && it[1] != pubKeyHex }, - privateKey = privateKey, - createdAt = createdAt - ) - } - - fun followHashtag(earlierVersion: ContactListEvent, hashtag: String, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): ContactListEvent { + fun followHashtag(earlierVersion: ContactListEvent, hashtag: String, keyPair: KeyPair, createdAt: Long = TimeUtils.now()): ContactListEvent { if (earlierVersion.isTaggedHash(hashtag)) return earlierVersion return create( content = earlierVersion.content, tags = earlierVersion.tags.plus(element = listOf("t", hashtag)), - privateKey = privateKey, + keyPair = keyPair, createdAt = createdAt ) } - fun followHashtag(earlierVersion: ContactListEvent, hashtag: String, pubKey: HexKey, createdAt: Long = TimeUtils.now()): ContactListEvent { - if (earlierVersion.isTaggedHash(hashtag)) return earlierVersion - - return create( - content = earlierVersion.content, - tags = earlierVersion.tags.plus(element = listOf("t", hashtag)), - pubKey = pubKey, - createdAt = createdAt - ) - } - - fun unfollowHashtag(earlierVersion: ContactListEvent, hashtag: String, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): ContactListEvent { + fun unfollowHashtag(earlierVersion: ContactListEvent, hashtag: String, keyPair: KeyPair, createdAt: Long = TimeUtils.now()): ContactListEvent { if (!earlierVersion.isTaggedHash(hashtag)) return earlierVersion return create( content = earlierVersion.content, tags = earlierVersion.tags.filter { it.size > 1 && !it[1].equals(hashtag, true) }, - privateKey = privateKey, + keyPair = keyPair, createdAt = createdAt ) } - fun unfollowHashtag(earlierVersion: ContactListEvent, hashtag: String, pubKey: HexKey, createdAt: Long = TimeUtils.now()): ContactListEvent { - if (!earlierVersion.isTaggedHash(hashtag)) return earlierVersion - - return create( - content = earlierVersion.content, - tags = earlierVersion.tags.filter { it.size > 1 && it[1] != hashtag }, - pubKey = pubKey, - createdAt = createdAt - ) - } - - fun followGeohash(earlierVersion: ContactListEvent, hashtag: String, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): ContactListEvent { + fun followGeohash(earlierVersion: ContactListEvent, hashtag: String, keyPair: KeyPair, createdAt: Long = TimeUtils.now()): ContactListEvent { if (earlierVersion.isTaggedGeoHash(hashtag)) return earlierVersion return create( content = earlierVersion.content, tags = earlierVersion.tags.plus(element = listOf("g", hashtag)), - privateKey = privateKey, + keyPair = keyPair, createdAt = createdAt ) } - fun unfollowGeohash(earlierVersion: ContactListEvent, hashtag: String, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): ContactListEvent { + fun unfollowGeohash(earlierVersion: ContactListEvent, hashtag: String, keyPair: KeyPair, createdAt: Long = TimeUtils.now()): ContactListEvent { if (!earlierVersion.isTaggedGeoHash(hashtag)) return earlierVersion return create( content = earlierVersion.content, tags = earlierVersion.tags.filter { it.size > 1 && it[1] != hashtag }, - privateKey = privateKey, + keyPair = keyPair, createdAt = createdAt ) } - fun followEvent(earlierVersion: ContactListEvent, idHex: String, pubKey: HexKey, privateKey: ByteArray?, createdAt: Long = TimeUtils.now()): ContactListEvent { - if (earlierVersion.isTaggedEvent(idHex)) return earlierVersion - - if (privateKey == null) { - return create( - content = earlierVersion.content, - tags = earlierVersion.tags.plus(element = listOf("e", idHex)), - pubKey = pubKey, - createdAt = createdAt - ) - } - - return create( - content = earlierVersion.content, - tags = earlierVersion.tags.plus(element = listOf("e", idHex)), - privateKey = privateKey, - createdAt = createdAt - ) - } - - fun followEvent(earlierVersion: ContactListEvent, idHex: String, pubKey: HexKey, createdAt: Long = TimeUtils.now()): ContactListEvent { + fun followEvent(earlierVersion: ContactListEvent, idHex: String, keyPair: KeyPair, createdAt: Long = TimeUtils.now()): ContactListEvent { if (earlierVersion.isTaggedEvent(idHex)) return earlierVersion return create( content = earlierVersion.content, tags = earlierVersion.tags.plus(element = listOf("e", idHex)), - pubKey = pubKey, + keyPair = keyPair, createdAt = createdAt ) } - fun unfollowEvent(earlierVersion: ContactListEvent, idHex: String, publicKey: HexKey, privateKey: ByteArray?, createdAt: Long = TimeUtils.now()): ContactListEvent { + fun unfollowEvent(earlierVersion: ContactListEvent, idHex: String, keyPair: KeyPair, createdAt: Long = TimeUtils.now()): ContactListEvent { if (!earlierVersion.isTaggedEvent(idHex)) return earlierVersion - if (privateKey == null) { - return create( - content = earlierVersion.content, - tags = earlierVersion.tags.filter { it.size > 1 && it[1] != idHex }, - pubKey = publicKey, - createdAt = createdAt - ) - } - return create( content = earlierVersion.content, tags = earlierVersion.tags.filter { it.size > 1 && it[1] != idHex }, - privateKey = privateKey, + keyPair = keyPair, createdAt = createdAt ) } - fun followAddressableEvent(earlierVersion: ContactListEvent, aTag: ATag, pubKey: HexKey, privateKey: ByteArray?, createdAt: Long = TimeUtils.now()): ContactListEvent { - if (earlierVersion.isTaggedAddressableNote(aTag.toTag())) return earlierVersion - - if (privateKey == null) { - return create( - content = earlierVersion.content, - tags = earlierVersion.tags.plus(element = listOfNotNull("a", aTag.toTag(), aTag.relay)), - pubKey = pubKey, - createdAt = createdAt - ) - } - - return create( - content = earlierVersion.content, - tags = earlierVersion.tags.plus(element = listOfNotNull("a", aTag.toTag(), aTag.relay)), - privateKey = privateKey, - createdAt = createdAt - ) - } - - fun followAddressableEvent(earlierVersion: ContactListEvent, aTag: ATag, pubKey: HexKey, createdAt: Long = TimeUtils.now()): ContactListEvent { + fun followAddressableEvent(earlierVersion: ContactListEvent, aTag: ATag, keyPair: KeyPair, createdAt: Long = TimeUtils.now()): ContactListEvent { if (earlierVersion.isTaggedAddressableNote(aTag.toTag())) return earlierVersion return create( content = earlierVersion.content, tags = earlierVersion.tags.plus(element = listOfNotNull("a", aTag.toTag(), aTag.relay)), - pubKey = pubKey, + keyPair = keyPair, createdAt = createdAt ) } - fun unfollowAddressableEvent(earlierVersion: ContactListEvent, aTag: ATag, pubKey: HexKey, privateKey: ByteArray?, createdAt: Long = TimeUtils.now()): ContactListEvent { + fun unfollowAddressableEvent(earlierVersion: ContactListEvent, aTag: ATag, keyPair: KeyPair, createdAt: Long = TimeUtils.now()): ContactListEvent { if (!earlierVersion.isTaggedAddressableNote(aTag.toTag())) return earlierVersion - if (privateKey == null) { - return create( - content = earlierVersion.content, - tags = earlierVersion.tags.filter { it.size > 1 && it[1] != aTag.toTag() }, - pubKey = pubKey, - createdAt = createdAt - ) - } - return create( content = earlierVersion.content, tags = earlierVersion.tags.filter { it.size > 1 && it[1] != aTag.toTag() }, - privateKey = privateKey, + keyPair = keyPair, createdAt = createdAt ) } - fun updateRelayList(earlierVersion: ContactListEvent, relayUse: Map?, pubKey: HexKey, privateKey: ByteArray?, createdAt: Long = TimeUtils.now()): ContactListEvent { + fun updateRelayList(earlierVersion: ContactListEvent, relayUse: Map?, keyPair: KeyPair, createdAt: Long = TimeUtils.now()): ContactListEvent { val content = if (relayUse != null) { mapper.writeValueAsString(relayUse) } else { "" } - if (privateKey == null) { - return create( - content = content, - tags = earlierVersion.tags, - pubKey = pubKey, - createdAt = createdAt - ) - } - return create( content = content, tags = earlierVersion.tags, - privateKey = privateKey, + keyPair = keyPair, createdAt = createdAt ) } - fun create(content: String, tags: List>, pubKey: HexKey, createdAt: Long = TimeUtils.now()): ContactListEvent { + fun create( + content: String, + tags: List>, + keyPair: KeyPair, + createdAt: Long = TimeUtils.now() + ): ContactListEvent { + val pubKey = keyPair.pubKey.toHexKey() val id = generateId(pubKey, createdAt, kind, tags, content) - return ContactListEvent(id.toHexKey(), pubKey, createdAt, tags, content, "") - } - - fun create(content: String, tags: List>, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): ContactListEvent { - val pubKey = CryptoUtils.pubkeyCreate(privateKey).toHexKey() - val id = generateId(pubKey, createdAt, kind, tags, content) - val sig = CryptoUtils.sign(id, privateKey) - return ContactListEvent(id.toHexKey(), pubKey, createdAt, tags, content, sig.toHexKey()) + val sig = if (keyPair.privKey == null) null else CryptoUtils.sign(id, keyPair.privKey) + return ContactListEvent(id.toHexKey(), pubKey, createdAt, tags, content, sig?.toHexKey() ?: "") } }