diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/database/TorchDatabase.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/database/TorchDatabase.kt index 23f5de25..a0b619da 100644 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/database/TorchDatabase.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/database/TorchDatabase.kt @@ -5,45 +5,50 @@ import androidx.room3.RoomDatabase import androidx.room3.TypeConverters import androidx.room3.immediateTransaction import androidx.room3.useWriterConnection +import at.torch.compose.database.dao.MarmotKeyPackageBundleDao +import at.torch.compose.database.dao.MarmotKeyPackageDao +import at.torch.compose.database.model.MarmotKeyPackageBundle import kotlin.time.Instant val GENESIS_AT = Instant.fromEpochMilliseconds(1231006505000L) @Database( entities = [ - _root_ide_package_.at.torch.compose.database.model.BroadcastNostrEventReceipt::class, - _root_ide_package_.at.torch.compose.database.model.BroadcastNostrEventRequest::class, - _root_ide_package_.at.torch.compose.database.model.Connection::class, - _root_ide_package_.at.torch.compose.database.model.ChatMessage::class, - _root_ide_package_.at.torch.compose.database.model.ChatMessageBroadcastNostrEventRequestRelation::class, - _root_ide_package_.at.torch.compose.database.model.ChatMessageBroadcastNostrEventReceiptRelation::class, - _root_ide_package_.at.torch.compose.database.model.ChatMessageNostrEventRelation::class, - _root_ide_package_.at.torch.compose.database.model.ChatRoom::class, - _root_ide_package_.at.torch.compose.database.model.InReplyToRelation::class, - _root_ide_package_.at.torch.compose.database.model.GiftWrapMessage::class, - _root_ide_package_.at.torch.compose.database.model.GiftWrapSeal::class, - _root_ide_package_.at.torch.compose.database.model.GiftWrapPayload::class, - _root_ide_package_.at.torch.compose.database.model.Mention::class, - _root_ide_package_.at.torch.compose.database.model.NegentropySynchronizeRequest::class, - _root_ide_package_.at.torch.compose.database.model.NegentropySynchronizeResult::class, - _root_ide_package_.at.torch.compose.database.model.NostrEvent::class, - _root_ide_package_.at.torch.compose.database.model.NostrEventRelay::class, - _root_ide_package_.at.torch.compose.database.model.Participant::class, - _root_ide_package_.at.torch.compose.database.model.Post::class, - _root_ide_package_.at.torch.compose.database.model.Profile::class, - _root_ide_package_.at.torch.compose.database.model.QuotedRelation::class, - _root_ide_package_.at.torch.compose.database.model.Reaction::class, - _root_ide_package_.at.torch.compose.database.model.RecentSearch::class, - _root_ide_package_.at.torch.compose.database.model.Relay::class, - _root_ide_package_.at.torch.compose.database.model.RepostedRelation::class, - _root_ide_package_.at.torch.compose.database.model.SynchronizeNostrEventRequest::class, - _root_ide_package_.at.torch.compose.database.model.SynchronizeNostrEventResult::class, - _root_ide_package_.at.torch.compose.database.model.UnsignedNostrEvent::class, - _root_ide_package_.at.torch.compose.database.model.Zap::class + at.torch.compose.database.model.BroadcastNostrEventReceipt::class, + at.torch.compose.database.model.BroadcastNostrEventRequest::class, + at.torch.compose.database.model.Connection::class, + at.torch.compose.database.model.ChatMessage::class, + at.torch.compose.database.model.ChatMessageBroadcastNostrEventRequestRelation::class, + at.torch.compose.database.model.ChatMessageBroadcastNostrEventReceiptRelation::class, + at.torch.compose.database.model.ChatMessageNostrEventRelation::class, + at.torch.compose.database.model.ChatRoom::class, + at.torch.compose.database.model.GiftWrapMessage::class, + at.torch.compose.database.model.GiftWrapSeal::class, + at.torch.compose.database.model.GiftWrapPayload::class, + at.torch.compose.database.model.InReplyToRelation::class, + at.torch.compose.database.model.MarmotKeyPackage::class, + at.torch.compose.database.model.MarmotKeyPackageBundle::class, + at.torch.compose.database.model.Mention::class, + at.torch.compose.database.model.NegentropySynchronizeRequest::class, + at.torch.compose.database.model.NegentropySynchronizeResult::class, + at.torch.compose.database.model.NostrEvent::class, + at.torch.compose.database.model.NostrEventRelay::class, + at.torch.compose.database.model.Participant::class, + at.torch.compose.database.model.Post::class, + at.torch.compose.database.model.Profile::class, + at.torch.compose.database.model.QuotedRelation::class, + at.torch.compose.database.model.Reaction::class, + at.torch.compose.database.model.RecentSearch::class, + at.torch.compose.database.model.Relay::class, + at.torch.compose.database.model.RepostedRelation::class, + at.torch.compose.database.model.SynchronizeNostrEventRequest::class, + at.torch.compose.database.model.SynchronizeNostrEventResult::class, + at.torch.compose.database.model.UnsignedNostrEvent::class, + at.torch.compose.database.model.Zap::class ], version = 1 ) -@TypeConverters(_root_ide_package_.at.torch.compose.database.converters.AuxConverters::class) +@TypeConverters(at.torch.compose.database.converters.AuxConverters::class) abstract class TorchDatabase: RoomDatabase() { abstract fun broadcastNostrEventReceiptDao(): at.torch.compose.database.dao.BroadcastNostrEventReceiptDao abstract fun broadcastNostrEventRequestDao(): at.torch.compose.database.dao.BroadcastNostrEventRequestDao @@ -68,6 +73,10 @@ abstract class TorchDatabase: RoomDatabase() { abstract fun inReplyToRelationDao(): at.torch.compose.database.dao.InReplyToRelationDao + abstract fun marmotKeyPackageDao(): MarmotKeyPackageDao + + abstract fun marmotKeyPackageBundleDao(): MarmotKeyPackageBundleDao + abstract fun mentionDao(): at.torch.compose.database.dao.MentionDao abstract fun negentropySynchronizeRequestDao(): at.torch.compose.database.dao.NegentropySynchronizeRequestDao diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/database/dao/MarmotKeyPackageBundleDao.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/database/dao/MarmotKeyPackageBundleDao.kt new file mode 100644 index 00000000..c36a768e --- /dev/null +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/database/dao/MarmotKeyPackageBundleDao.kt @@ -0,0 +1,15 @@ +package at.torch.compose.database.dao + +import androidx.room3.Dao +import androidx.room3.Insert +import androidx.room3.OnConflictStrategy.Companion.IGNORE +import androidx.room3.Upsert +import at.torch.compose.database.model.MarmotKeyPackage +import at.torch.compose.database.model.MarmotKeyPackageBundle +import at.torch.compose.database.model.Mention + +@Dao +interface MarmotKeyPackageBundleDao { + @Upsert + suspend fun upsert(marmotKeyPackageBundle: MarmotKeyPackageBundle) +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/database/dao/MarmotKeyPackageDao.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/database/dao/MarmotKeyPackageDao.kt new file mode 100644 index 00000000..ffdc5d0c --- /dev/null +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/database/dao/MarmotKeyPackageDao.kt @@ -0,0 +1,15 @@ +package at.torch.compose.database.dao + +import androidx.room3.Dao +import androidx.room3.Insert +import androidx.room3.OnConflictStrategy.Companion.IGNORE +import androidx.room3.Upsert +import at.torch.compose.database.model.MarmotKeyPackage +import at.torch.compose.database.model.Mention + +@Dao +interface MarmotKeyPackageDao { + + @Upsert + suspend fun upsert(marmotKeyPackage: MarmotKeyPackage) +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/MarmotKeyPackage.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/MarmotKeyPackage.kt new file mode 100644 index 00000000..8e1ea915 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/MarmotKeyPackage.kt @@ -0,0 +1,68 @@ +package at.torch.compose.database.model + +import androidx.room3.Entity +import androidx.room3.ForeignKey +import androidx.room3.PrimaryKey +import at.torch.compose.database.model.traits.BroadcastableEntity +import at.torch.compose.database.model.traits.LocalStoreEntity +import at.torch.compose.database.model.traits.SoftDeletableEntity +import at.torch.compose.database.model.traits.TimestampedEntity +import com.vitorpamplona.quartz.nip01Core.core.HexKey +import kotlin.time.Clock +import kotlin.time.Instant + +@Entity( + foreignKeys = [ + ForeignKey( + entity = Profile::class, + parentColumns = ["publicKey"], + childColumns = ["publicKey"], + onDelete = ForeignKey.CASCADE, + ), + ] +) +data class MarmotKeyPackage( + @PrimaryKey(autoGenerate = true) + val id: Long = 0, + + val publicKey: HexKey, + + val tlsEncodedMarmotKeyPackage: ByteArray, + + override val createdAt: Instant = Clock.System.now(), + override val updatedAt: Instant = Clock.System.now(), + override val savedAt: Instant = Clock.System.now(), + override val deletedAt: Instant? = null, + override val broadcastedAt: Instant? = null, +): TimestampedEntity, LocalStoreEntity, BroadcastableEntity, SoftDeletableEntity { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + + other as MarmotKeyPackage + + if (id != other.id) return false + if (publicKey != other.publicKey) return false + if (!tlsEncodedMarmotKeyPackage.contentEquals(other.tlsEncodedMarmotKeyPackage)) return false + if (createdAt != other.createdAt) return false + if (updatedAt != other.updatedAt) return false + if (savedAt != other.savedAt) return false + if (deletedAt != other.deletedAt) return false + if (broadcastedAt != other.broadcastedAt) return false + + return true + } + + override fun hashCode(): Int { + var result = id.hashCode() + result = 31 * result + publicKey.hashCode() + result = 31 * result + tlsEncodedMarmotKeyPackage.contentHashCode() + result = 31 * result + createdAt.hashCode() + result = 31 * result + updatedAt.hashCode() + result = 31 * result + savedAt.hashCode() + result = 31 * result + (deletedAt?.hashCode() ?: 0) + result = 31 * result + (broadcastedAt?.hashCode() ?: 0) + return result + } + +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/MarmotKeyPackageBundle.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/MarmotKeyPackageBundle.kt new file mode 100644 index 00000000..5af88fb2 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/MarmotKeyPackageBundle.kt @@ -0,0 +1,42 @@ +package at.torch.compose.database.model + +import androidx.room3.Entity +import androidx.room3.ForeignKey +import androidx.room3.PrimaryKey +import at.torch.compose.database.model.traits.BroadcastableEntity +import at.torch.compose.database.model.traits.LocalStoreEntity +import at.torch.compose.database.model.traits.SoftDeletableEntity +import at.torch.compose.database.model.traits.TimestampedEntity +import com.vitorpamplona.quartz.nip01Core.core.HexKey +import kotlin.time.Clock +import kotlin.time.Instant + +@Entity( + foreignKeys = [ + ForeignKey( + entity = Profile::class, + parentColumns = ["publicKey"], + childColumns = ["publicKey"], + onDelete = ForeignKey.CASCADE, + ), + ] +) +data class MarmotKeyPackageBundle( + @PrimaryKey(autoGenerate = true) + val id: Long = 0, + + val publicKey: HexKey, + + val tlsEncodedMarmotKeyPackage: String, + val ncryptsecInitPrivateKey: String, + val ncryptsecEncryptionPrivateKey: String, + val ncryptsecSignaturePrivateKey: String, + + override val createdAt: Instant = Clock.System.now(), + override val updatedAt: Instant = Clock.System.now(), + override val savedAt: Instant = Clock.System.now(), + override val deletedAt: Instant? = null, + override val broadcastedAt: Instant? = null, +): TimestampedEntity, LocalStoreEntity, BroadcastableEntity, SoftDeletableEntity { + +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/Mention.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/Mention.kt index ee9e09a3..f09cc621 100644 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/Mention.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/database/model/Mention.kt @@ -3,6 +3,10 @@ package at.torch.compose.database.model import androidx.room3.Entity import androidx.room3.ForeignKey import androidx.room3.PrimaryKey +import at.torch.compose.database.model.traits.BroadcastableEntity +import at.torch.compose.database.model.traits.LocalStoreEntity +import at.torch.compose.database.model.traits.SoftDeletableEntity +import at.torch.compose.database.model.traits.TimestampedEntity import com.vitorpamplona.quartz.nip01Core.core.HexKey import kotlin.time.Clock import kotlin.time.Instant @@ -37,7 +41,7 @@ data class Mention( override val savedAt: Instant = Clock.System.now(), override val deletedAt: Instant? = null, override val broadcastedAt: Instant? = null, -): at.torch.compose.database.model.traits.TimestampedEntity, - at.torch.compose.database.model.traits.LocalStoreEntity, - at.torch.compose.database.model.traits.BroadcastableEntity, - at.torch.compose.database.model.traits.SoftDeletableEntity +): TimestampedEntity, + LocalStoreEntity, + BroadcastableEntity, + SoftDeletableEntity diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/database/repository/DatabaseMarmotRepository.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/database/repository/DatabaseMarmotRepository.kt new file mode 100644 index 00000000..96c3baa9 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/database/repository/DatabaseMarmotRepository.kt @@ -0,0 +1,37 @@ +package at.torch.compose.database.repository + +import at.torch.compose.database.TorchDatabase +import at.torch.compose.database.model.MarmotKeyPackageBundle +import at.torch.compose.extensions.toHex +import at.torch.compose.repository.MarmotRepository +import com.vitorpamplona.quartz.marmot.mls.codec.TlsWriter +import com.vitorpamplona.quartz.marmot.mls.messages.KeyPackageBundle +import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.nip49PrivKeyEnc.Nip49 + +class DatabaseMarmotRepository( + val database: TorchDatabase +): MarmotRepository { + override suspend fun saveMarmotKeyPackageBundle( + publicKey: HexKey, + keyPackageBundle: KeyPackageBundle, + nsecPassword: String + ) { + val tlsWriter = TlsWriter() + + keyPackageBundle.keyPackage.encodeTls(tlsWriter) + + val nip49 = Nip49() + + database.marmotKeyPackageBundleDao().upsert( + MarmotKeyPackageBundle( + publicKey = publicKey, + tlsEncodedMarmotKeyPackage = tlsWriter.toByteArray().toHex(), + ncryptsecInitPrivateKey = nip49.encrypt(keyPackageBundle.initPrivateKey.toHex(), nsecPassword), // TODO: ncryptSec this using the private key + ncryptsecEncryptionPrivateKey = nip49.encrypt(keyPackageBundle.encryptionPrivateKey.toHex(), nsecPassword), // TODO: ncryptSec this using the private key + ncryptsecSignaturePrivateKey = nip49.encrypt(keyPackageBundle.signaturePrivateKey.toHex(), nsecPassword) // TODO: ncryptSec this using the private key + ) + ) + + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/database/repository/DatabaseNostrRepository.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/database/repository/DatabaseNostrRepository.kt index e52fa872..3236c726 100644 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/database/repository/DatabaseNostrRepository.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/database/repository/DatabaseNostrRepository.kt @@ -1,9 +1,6 @@ package at.torch.compose.database.repository -import at.torch.compose.database.GENESIS_AT -import at.torch.compose.database.model.BroadcastNostrEventReceipt -import at.torch.compose.database.model.ChatMessageBroadcastNostrEventReceiptRelation -import at.torch.compose.database.model.RecentSearch +import at.torch.compose.database.model.MarmotKeyPackageBundle import at.torch.compose.database.model.UnsignedNostrEvent import at.torch.compose.nostr.Relays import co.touchlab.kermit.Logger @@ -11,6 +8,7 @@ import com.vitorpamplona.quartz.marmot.mip00KeyPackages.KeyPackageEvent import com.vitorpamplona.quartz.marmot.mip00KeyPackages.KeyPackageRelayListEvent import com.vitorpamplona.quartz.marmot.mip00KeyPackages.KeyPackageRotationManager.Companion.KEY_PACKAGE_LIFETIME_SECONDS import com.vitorpamplona.quartz.marmot.mip00KeyPackages.KeyPackageUtils +import com.vitorpamplona.quartz.marmot.mls.codec.TlsWriter import com.vitorpamplona.quartz.marmot.mls.crypto.Ed25519 import com.vitorpamplona.quartz.marmot.mls.crypto.MlsCryptoProvider import com.vitorpamplona.quartz.marmot.mls.crypto.X25519 @@ -48,14 +46,11 @@ import com.vitorpamplona.quartz.nip18Reposts.quotes.QEventTag import com.vitorpamplona.quartz.nip18Reposts.quotes.quotes import com.vitorpamplona.quartz.nip21UriScheme.toNostrUri import com.vitorpamplona.quartz.nip25Reactions.ReactionEvent -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.nip57Zaps.LnZapEvent -import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay @@ -118,7 +113,7 @@ class DatabaseNostrRepository( publicKey: HexKey, name: String?, biography: String? - ) { + ): KeyPackageBundle { val profileEventTemplate = MetadataEvent.createNew( name = name, about = biography, @@ -213,8 +208,6 @@ class DatabaseNostrRepository( val identity = publicKey.hexToByteArray() val bundle = generateKeyPackage(identity, dTag) - // TODO: Save the bundle? - val keyPackageBytes = bundle.keyPackage.toTlsBytes() val keyPackageBase64 = Base64.encode(keyPackageBytes) val keyPackageRef = bundle.keyPackage.reference().toHexKey() @@ -236,6 +229,8 @@ class DatabaseNostrRepository( ) saveUnsignedNostrEvents(unsignedNostrEvents) + + return bundle } private fun generateKeyPackage( diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/repository/MarmotRepository.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/repository/MarmotRepository.kt new file mode 100644 index 00000000..4454b6d7 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/repository/MarmotRepository.kt @@ -0,0 +1,26 @@ +package at.torch.compose.repository + +import com.vitorpamplona.quartz.marmot.mls.messages.KeyPackageBundle +import com.vitorpamplona.quartz.nip01Core.core.HexKey + +interface MarmotRepository { + + suspend fun saveMarmotKeyPackageBundle( + publicKey: HexKey, + keyPackageBundle: KeyPackageBundle, + nsecPassword: String + ) + + companion object { + private val NO_OP_MARMOT_KEY_PACKAGE_BUNDLE = object: MarmotRepository { + override suspend fun saveMarmotKeyPackageBundle( + publicKey: HexKey, + keyPackageBundle: KeyPackageBundle, + nsecPassword: String + ) { + TODO("Not yet implemented") + } + + } + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/repository/NostrRepository.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/repository/NostrRepository.kt index ac5876dc..20ae3aa4 100644 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/repository/NostrRepository.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/repository/NostrRepository.kt @@ -1,5 +1,6 @@ package at.torch.compose.repository +import com.vitorpamplona.quartz.marmot.mls.messages.KeyPackageBundle import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.Kind import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair @@ -24,7 +25,7 @@ interface NostrRepository { publicKey: HexKey, name: String?, biography: String? - ) + ): KeyPackageBundle suspend fun signInToProfile( publicKey: HexKey @@ -155,7 +156,8 @@ interface NostrRepository { publicKey: HexKey, name: String?, biography: String? - ) { + ): KeyPackageBundle { + TODO("") } override suspend fun signInToProfile(publicKey: HexKey) { diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/ui/view/model/ChatRoomCreationViewModel.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/ui/view/model/ChatRoomCreationViewModel.kt index 6b31dc54..ae5737b1 100644 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/ui/view/model/ChatRoomCreationViewModel.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/ui/view/model/ChatRoomCreationViewModel.kt @@ -90,6 +90,7 @@ class ChatRoomCreationViewModel( viewModelScope.launch(Dispatchers.Main) { if (localChatRoom != null) { // TODO: Broadcast the thing... + // TODO: Navigate to invitation screen... onNavigateToChatRoom.invoke( ChatRoomDetailRoute( diff --git a/composeApp/src/commonMain/kotlin/at/torch/compose/ui/view/model/CreateProfileViewModel.kt b/composeApp/src/commonMain/kotlin/at/torch/compose/ui/view/model/CreateProfileViewModel.kt index 3c7aa29a..64a46313 100644 --- a/composeApp/src/commonMain/kotlin/at/torch/compose/ui/view/model/CreateProfileViewModel.kt +++ b/composeApp/src/commonMain/kotlin/at/torch/compose/ui/view/model/CreateProfileViewModel.kt @@ -10,6 +10,7 @@ import androidx.lifecycle.viewmodel.initializer import androidx.lifecycle.viewmodel.viewModelFactory import at.torch.compose.ui.view.state.form.CreateProfileFormState import androidx.lifecycle.viewModelScope +import at.torch.compose.repository.MarmotRepository import co.touchlab.kermit.Logger import fr.acinq.bitcoin.Chain import fr.acinq.bitcoin.MnemonicCode @@ -18,6 +19,7 @@ import fr.acinq.lightning.Lightning import fr.acinq.lightning.crypto.LocalKeyManager import fr.acinq.phoenix.managers.NodeParamsManager import fr.acinq.phoenix.managers.nostrPublicKey +import fr.acinq.phoenix.managers.nsecPassword import fr.acinq.phoenix.utils.MnemonicLanguage import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.Dispatchers @@ -27,19 +29,22 @@ import kotlinx.coroutines.launch class CreateProfileViewModel( val initialCreateProfileUIState: CreateProfileUIState, val createProfileFormState: CreateProfileFormState = CreateProfileFormState(), - val nostrRepository: NostrRepository + val nostrRepository: NostrRepository, + val marmotRepository: MarmotRepository ): ViewModel() { companion object { private const val TAG = "CreateAccountViewModel" fun factory( initialCreateProfileUIState: CreateProfileUIState, - nostrRepository: NostrRepository + nostrRepository: NostrRepository, + marmotRepository: MarmotRepository ): ViewModelProvider.Factory = viewModelFactory { initializer { CreateProfileViewModel( initialCreateProfileUIState, - nostrRepository = nostrRepository + nostrRepository = nostrRepository, + marmotRepository = marmotRepository ) } } @@ -100,12 +105,17 @@ class CreateProfileViewModel( ) val pubkey = localKeyManager.nostrPublicKey() - logger.d("NostrKey: $pubkey") - nostrRepository.createNewProfile( + val keyPackageBundle = nostrRepository.createNewProfile( pubkey, name = createProfileFormState.nameField.textFieldState.text.toString(), biography = createProfileFormState.biographyField.textFieldState.text.toString() ) + + marmotRepository.saveMarmotKeyPackageBundle( + publicKey = pubkey, + keyPackageBundle, + nsecPassword = localKeyManager.nsecPassword() + ) } } diff --git a/composeApp/src/commonMain/kotlin/fr/acinq/phoenix/managers/WalletManager.kt b/composeApp/src/commonMain/kotlin/fr/acinq/phoenix/managers/WalletManager.kt index 12ad36e2..e56f12ae 100644 --- a/composeApp/src/commonMain/kotlin/fr/acinq/phoenix/managers/WalletManager.kt +++ b/composeApp/src/commonMain/kotlin/fr/acinq/phoenix/managers/WalletManager.kt @@ -102,6 +102,12 @@ fun LocalKeyManager.nostrPrivateKey(): PrivateKey { return derivePrivateKey(path).privateKey } +fun LocalKeyManager.nsecPassword(): String { + return Crypto.hash160( + nostrPrivateKey().value + ).byteVector().toHex() +} + fun LocalKeyManager.nostrPublicKey(): HexKey { return KeyPair( privKey = nostrPrivateKey().value.toByteArray()