From 4e23206537424ea415282bcb8f5718ae786a066b Mon Sep 17 00:00:00 2001 From: Kgothatso Ngako Date: Mon, 30 Mar 2026 20:38:01 +0200 Subject: [PATCH] Increase account creation functionality. --- .../1.json | 11 +- .../database/model/UnsignedNostrEvent.kt | 1 + .../repository/DatabaseNostrRepository.kt | 120 ++++++++++++++++-- .../kotlin/ac/aux/compose/nostr/Relays.kt | 29 +++++ .../ui/view/model/NavigationViewModel.kt | 3 +- 5 files changed, 146 insertions(+), 18 deletions(-) diff --git a/composeApp/schemas/ac.aux.compose.database.AuxDatabase/1.json b/composeApp/schemas/ac.aux.compose.database.AuxDatabase/1.json index f46bdc03..3f8ff5dc 100644 --- a/composeApp/schemas/ac.aux.compose.database.AuxDatabase/1.json +++ b/composeApp/schemas/ac.aux.compose.database.AuxDatabase/1.json @@ -2,7 +2,7 @@ "formatVersion": 1, "database": { "version": 1, - "identityHash": "9a3031f0a4cb56c9b5d6c26be0f48a3c", + "identityHash": "40dc44925e9b6000404e2cc5e781e4c2", "entities": [ { "tableName": "BroadcastNostrEventReceipt", @@ -1074,7 +1074,7 @@ }, { "tableName": "UnsignedNostrEvent", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `pubKey` TEXT NOT NULL, `kind` INTEGER NOT NULL, `tags` TEXT NOT NULL, `content` TEXT NOT NULL, `signedAt` INTEGER, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `deletedAt` INTEGER, `broadcastedAt` INTEGER)", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `pubKey` TEXT NOT NULL, `kind` INTEGER NOT NULL, `tags` TEXT NOT NULL, `privateTags` TEXT, `content` TEXT NOT NULL, `signedAt` INTEGER, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `deletedAt` INTEGER, `broadcastedAt` INTEGER)", "fields": [ { "fieldPath": "id", @@ -1100,6 +1100,11 @@ "affinity": "TEXT", "notNull": true }, + { + "fieldPath": "privateTags", + "columnName": "privateTags", + "affinity": "TEXT" + }, { "fieldPath": "content", "columnName": "content", @@ -1335,7 +1340,7 @@ ], "setupQueries": [ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '9a3031f0a4cb56c9b5d6c26be0f48a3c')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '40dc44925e9b6000404e2cc5e781e4c2')" ] } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/UnsignedNostrEvent.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/UnsignedNostrEvent.kt index 2cd5f0ff..e914a10e 100644 --- a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/UnsignedNostrEvent.kt +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/model/UnsignedNostrEvent.kt @@ -35,6 +35,7 @@ data class UnsignedNostrEvent( val pubKey: HexKey, val kind: Kind, val tags: TagArray, + val privateTags: TagArray? = null, val content: String, val signedAt: Instant? = null, diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/repository/DatabaseNostrRepository.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/repository/DatabaseNostrRepository.kt index 7ae90a0b..5fb8ad74 100644 --- a/composeApp/src/commonMain/kotlin/ac/aux/compose/database/repository/DatabaseNostrRepository.kt +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/database/repository/DatabaseNostrRepository.kt @@ -9,13 +9,29 @@ import ac.aux.compose.database.model.SynchronizeNostrEventRequest import ac.aux.compose.database.model.UnsignedNostrEvent import ac.aux.compose.database.model.intermdiate.LocalBroadcastNostrEventRequest import ac.aux.compose.database.model.intermdiate.LocalProfile +import ac.aux.compose.nostr.Relays import ac.aux.compose.repository.NostrRepository import co.touchlab.kermit.Logger import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent +import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent +import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent.Companion.ALT +import com.vitorpamplona.quartz.nip02FollowList.RelaySet +import com.vitorpamplona.quartz.nip02FollowList.tags.ContactTag import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent +import com.vitorpamplona.quartz.nip17Dm.settings.ChatMessageRelayListEvent +import com.vitorpamplona.quartz.nip28PublicChat.list.ChannelListEvent +import com.vitorpamplona.quartz.nip31Alts.AltTag +import com.vitorpamplona.quartz.nip50Search.SearchRelayListEvent +import com.vitorpamplona.quartz.nip51Lists.relayLists.IndexerRelayListEvent +import com.vitorpamplona.quartz.nip51Lists.relayLists.RelayFeedsListEvent +import com.vitorpamplona.quartz.nip51Lists.tags.RelayTag +import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow +import kotlin.collections.emptyMap +import kotlin.collections.plus import kotlin.time.Clock import kotlin.time.Instant @@ -77,23 +93,99 @@ class DatabaseNostrRepository( if (unsignedNostrEvent == null) { onError.invoke() - } else if (unsignedNostrEvent.kind == 0 ) { + } else if (unsignedNostrEvent.kind == 0) { // Look busy for the onboarding screen delay(3_500) -// if (unsignedNostrEvent.signedAt != null) { -// // Submit a SyncNostrEventRequest -// synchronizationRelayURLs.forEach { relayUrl -> -// database.synchronizeNostrEventRequestDao().upsert( -// SynchronizeNostrEventRequest( -// authorPublicKeys = arrayOf(unsignedNostrEvent.pubKey), -// kinds = arrayOf(0), -// status = "pending", -// relayURL = relayUrl -// ) -// ) -// } -// } + + if (unsignedNostrEvent.signedAt == null) { + // Save ContactListNostrEvent + val followUsers = listOf(ContactTag(publicKey, null, null)) + val contactListTagList = listOf(AltTag.assemble(ContactListEvent.ALT)) + + followUsers.map { it.toTagArray() } + + saveUnsignedNostrEvent( + UnsignedNostrEvent( + pubKey = publicKey, + kind = ContactListEvent.KIND, + tags = contactListTagList.toTypedArray(), + content = RelaySet.assemble( + emptyMap() + ) + ) + ) + + // Save AdvertisedRelayListEvent + saveUnsignedNostrEvent( + UnsignedNostrEvent( + pubKey = publicKey, + kind = AdvertisedRelayListEvent.KIND, + tags = Relays.DefaultNIP65List.map{ it.toTagArray() }.toTypedArray(), + content = "" + ) + ) + // Save ChatMessageRelayListEvent + saveUnsignedNostrEvent( + UnsignedNostrEvent( + pubKey = publicKey, + kind = ChatMessageRelayListEvent.KIND, + tags = Relays.DefaultDMRelayList.map{ RelayTag.assemble(it) } + .plusElement( + AltTag.assemble("Relay list to receive private messages") + ).toTypedArray(), + content = "" + ) + ) + // Save SearchRelayListEvent + saveUnsignedNostrEvent( + UnsignedNostrEvent( + pubKey = publicKey, + kind = SearchRelayListEvent.KIND, + tags = Relays.DefaultSearchRelayList.map{ RelayTag.assemble(it) } + .plus( + SearchRelayListEvent.ALT_TAG + ).toTypedArray(), + privateTags = emptyArray(), + content = "" + ) + ) + // Save IndexerRelayListEvent + saveUnsignedNostrEvent( + UnsignedNostrEvent( + pubKey = publicKey, + kind = IndexerRelayListEvent.KIND, + tags = arrayOf(AltTag.assemble(IndexerRelayListEvent.ALT)), + privateTags = Relays.DefaultIndexerRelayList.map { RelayTag.assemble(it) }.toTypedArray() , + content = "" + ) + ) + // Save ChannelListEvent + saveUnsignedNostrEvent( + UnsignedNostrEvent( + pubKey = publicKey, + kind = ChannelListEvent.KIND, + tags = arrayOf( + AltTag.assemble( + ChannelListEvent.ALT + ) + ), + privateTags = Relays.DefaultChannels.map { it.toTagArray() }.toTypedArray(), + content = "" + ) + ) + // Save RelayFeedsListEvent + saveUnsignedNostrEvent( + UnsignedNostrEvent( + pubKey = publicKey, + kind = RelayFeedsListEvent.KIND, + tags = arrayOf( + AltTag.assemble(RelayFeedsListEvent.ALT) + ), + privateTags = Relays.DefaultGlobalRelays.map { RelayTag.assemble(it)}.toTypedArray(), + content = "" + ) + ) + } } } diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/nostr/Relays.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/nostr/Relays.kt index 81e7fb8d..0b1e5854 100644 --- a/composeApp/src/commonMain/kotlin/ac/aux/compose/nostr/Relays.kt +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/nostr/Relays.kt @@ -1,6 +1,9 @@ package ac.aux.compose.nostr import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer +import com.vitorpamplona.quartz.nip28PublicChat.list.tags.ChannelTag +import com.vitorpamplona.quartz.nip65RelayList.tags.AdvertisedRelayInfo +import com.vitorpamplona.quartz.nip65RelayList.tags.AdvertisedRelayType object Relays { val nos = RelayUrlNormalizer.normalize("wss://nos.lol") @@ -33,4 +36,30 @@ object Relays { val bootstrapInboxRelaySet = setOf(damus, primal, mom, nos, bitcoiner, oxtr, yabu) val eventFinderRelaySet = setOf(wine, damus, primal, mom, nos, bitcoiner, oxtr) val eventPublishRelaySet = setOf(damus, primal, mom, nos, bitcoiner, oxtr) + + + val DefaultNIP65RelaySet = setOf(mom, nos, bitcoiner) + + val DefaultNIP65List = + listOf( + AdvertisedRelayInfo(mom, AdvertisedRelayType.BOTH), + AdvertisedRelayInfo(nos, AdvertisedRelayType.BOTH), + AdvertisedRelayInfo(bitcoiner, AdvertisedRelayType.BOTH), + ) + + val DefaultGlobalRelays = listOf(wine, news) + + val DefaultDMRelayList = listOf(auth, oxchat, nos) + + val DefaultSearchRelayList = setOf(wine, where, nostoday, antiprimal, ditto) + + val DefaultIndexerRelayList = setOf(purplepages, coracle, userkinds, yabu, nostr1) + + val DefaultChannels = + listOf( + // Anigma's Nostr + ChannelTag("25e5c82273a271cb1a840d0060391a0bf4965cafeb029d5ab55350b418953fbb", nos), + // Amethyst's Group + ChannelTag("42224859763652914db53052103f0b744df79dfc4efef7e950fc0802fc3df3c5", nos), + ) } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ac/aux/compose/ui/view/model/NavigationViewModel.kt b/composeApp/src/commonMain/kotlin/ac/aux/compose/ui/view/model/NavigationViewModel.kt index ad2cb523..7a5e23ea 100644 --- a/composeApp/src/commonMain/kotlin/ac/aux/compose/ui/view/model/NavigationViewModel.kt +++ b/composeApp/src/commonMain/kotlin/ac/aux/compose/ui/view/model/NavigationViewModel.kt @@ -17,6 +17,7 @@ import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip01Core.relay.commands.toRelay.ReqCmd import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync +import com.vitorpamplona.quartz.nip51Lists.encryption.PrivateTagsInContent import com.vitorpamplona.quartz.utils.text import io.ktor.client.HttpClient import io.ktor.client.plugins.websocket.WebSockets @@ -111,7 +112,7 @@ class NavigationViewModel( createdAt = unsignedNostrEvent.createdAt.epochSeconds, kind = unsignedNostrEvent.kind, tags = unsignedNostrEvent.tags, - content = unsignedNostrEvent.content + content = unsignedNostrEvent.privateTags?.let { PrivateTagsInContent.encryptNip44(it, tempSigner) } ?: unsignedNostrEvent.content ) nostrRepository.publishNostrEvent(