Save profile keypackage bundle
This commit is contained in:
1 parent
24cb4db9a9
commit
3b9be3a9dd
13 files changed
+281
-51
No files matched your search
@@ -5,45 +5,50 @@ import androidx.room3.RoomDatabase
|
|||||||
import androidx.room3.TypeConverters
|
import androidx.room3.TypeConverters
|
||||||
import androidx.room3.immediateTransaction
|
import androidx.room3.immediateTransaction
|
||||||
import androidx.room3.useWriterConnection
|
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
|
import kotlin.time.Instant
|
||||||
|
|
||||||
val GENESIS_AT = Instant.fromEpochMilliseconds(1231006505000L)
|
val GENESIS_AT = Instant.fromEpochMilliseconds(1231006505000L)
|
||||||
|
|
||||||
@Database(
|
@Database(
|
||||||
entities = [
|
entities = [
|
||||||
_root_ide_package_.at.torch.compose.database.model.BroadcastNostrEventReceipt::class,
|
at.torch.compose.database.model.BroadcastNostrEventReceipt::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.BroadcastNostrEventRequest::class,
|
at.torch.compose.database.model.BroadcastNostrEventRequest::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.Connection::class,
|
at.torch.compose.database.model.Connection::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.ChatMessage::class,
|
at.torch.compose.database.model.ChatMessage::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.ChatMessageBroadcastNostrEventRequestRelation::class,
|
at.torch.compose.database.model.ChatMessageBroadcastNostrEventRequestRelation::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.ChatMessageBroadcastNostrEventReceiptRelation::class,
|
at.torch.compose.database.model.ChatMessageBroadcastNostrEventReceiptRelation::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.ChatMessageNostrEventRelation::class,
|
at.torch.compose.database.model.ChatMessageNostrEventRelation::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.ChatRoom::class,
|
at.torch.compose.database.model.ChatRoom::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.InReplyToRelation::class,
|
at.torch.compose.database.model.GiftWrapMessage::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.GiftWrapMessage::class,
|
at.torch.compose.database.model.GiftWrapSeal::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.GiftWrapSeal::class,
|
at.torch.compose.database.model.GiftWrapPayload::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.GiftWrapPayload::class,
|
at.torch.compose.database.model.InReplyToRelation::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.Mention::class,
|
at.torch.compose.database.model.MarmotKeyPackage::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.NegentropySynchronizeRequest::class,
|
at.torch.compose.database.model.MarmotKeyPackageBundle::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.NegentropySynchronizeResult::class,
|
at.torch.compose.database.model.Mention::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.NostrEvent::class,
|
at.torch.compose.database.model.NegentropySynchronizeRequest::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.NostrEventRelay::class,
|
at.torch.compose.database.model.NegentropySynchronizeResult::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.Participant::class,
|
at.torch.compose.database.model.NostrEvent::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.Post::class,
|
at.torch.compose.database.model.NostrEventRelay::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.Profile::class,
|
at.torch.compose.database.model.Participant::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.QuotedRelation::class,
|
at.torch.compose.database.model.Post::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.Reaction::class,
|
at.torch.compose.database.model.Profile::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.RecentSearch::class,
|
at.torch.compose.database.model.QuotedRelation::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.Relay::class,
|
at.torch.compose.database.model.Reaction::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.RepostedRelation::class,
|
at.torch.compose.database.model.RecentSearch::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.SynchronizeNostrEventRequest::class,
|
at.torch.compose.database.model.Relay::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.SynchronizeNostrEventResult::class,
|
at.torch.compose.database.model.RepostedRelation::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.UnsignedNostrEvent::class,
|
at.torch.compose.database.model.SynchronizeNostrEventRequest::class,
|
||||||
_root_ide_package_.at.torch.compose.database.model.Zap::class
|
at.torch.compose.database.model.SynchronizeNostrEventResult::class,
|
||||||
|
at.torch.compose.database.model.UnsignedNostrEvent::class,
|
||||||
|
at.torch.compose.database.model.Zap::class
|
||||||
],
|
],
|
||||||
version = 1
|
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 class TorchDatabase: RoomDatabase() {
|
||||||
abstract fun broadcastNostrEventReceiptDao(): at.torch.compose.database.dao.BroadcastNostrEventReceiptDao
|
abstract fun broadcastNostrEventReceiptDao(): at.torch.compose.database.dao.BroadcastNostrEventReceiptDao
|
||||||
abstract fun broadcastNostrEventRequestDao(): at.torch.compose.database.dao.BroadcastNostrEventRequestDao
|
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 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 mentionDao(): at.torch.compose.database.dao.MentionDao
|
||||||
|
|
||||||
abstract fun negentropySynchronizeRequestDao(): at.torch.compose.database.dao.NegentropySynchronizeRequestDao
|
abstract fun negentropySynchronizeRequestDao(): at.torch.compose.database.dao.NegentropySynchronizeRequestDao
|
||||||
|
|||||||
+15
@@ -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)
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+42
@@ -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 {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -3,6 +3,10 @@ package at.torch.compose.database.model
|
|||||||
import androidx.room3.Entity
|
import androidx.room3.Entity
|
||||||
import androidx.room3.ForeignKey
|
import androidx.room3.ForeignKey
|
||||||
import androidx.room3.PrimaryKey
|
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 com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||||
import kotlin.time.Clock
|
import kotlin.time.Clock
|
||||||
import kotlin.time.Instant
|
import kotlin.time.Instant
|
||||||
@@ -37,7 +41,7 @@ data class Mention(
|
|||||||
override val savedAt: Instant = Clock.System.now(),
|
override val savedAt: Instant = Clock.System.now(),
|
||||||
override val deletedAt: Instant? = null,
|
override val deletedAt: Instant? = null,
|
||||||
override val broadcastedAt: Instant? = null,
|
override val broadcastedAt: Instant? = null,
|
||||||
): at.torch.compose.database.model.traits.TimestampedEntity,
|
): TimestampedEntity,
|
||||||
at.torch.compose.database.model.traits.LocalStoreEntity,
|
LocalStoreEntity,
|
||||||
at.torch.compose.database.model.traits.BroadcastableEntity,
|
BroadcastableEntity,
|
||||||
at.torch.compose.database.model.traits.SoftDeletableEntity
|
SoftDeletableEntity
|
||||||
+37
@@ -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
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-10
@@ -1,9 +1,6 @@
|
|||||||
package at.torch.compose.database.repository
|
package at.torch.compose.database.repository
|
||||||
|
|
||||||
import at.torch.compose.database.GENESIS_AT
|
import at.torch.compose.database.model.MarmotKeyPackageBundle
|
||||||
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.UnsignedNostrEvent
|
import at.torch.compose.database.model.UnsignedNostrEvent
|
||||||
import at.torch.compose.nostr.Relays
|
import at.torch.compose.nostr.Relays
|
||||||
import co.touchlab.kermit.Logger
|
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.KeyPackageRelayListEvent
|
||||||
import com.vitorpamplona.quartz.marmot.mip00KeyPackages.KeyPackageRotationManager.Companion.KEY_PACKAGE_LIFETIME_SECONDS
|
import com.vitorpamplona.quartz.marmot.mip00KeyPackages.KeyPackageRotationManager.Companion.KEY_PACKAGE_LIFETIME_SECONDS
|
||||||
import com.vitorpamplona.quartz.marmot.mip00KeyPackages.KeyPackageUtils
|
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.Ed25519
|
||||||
import com.vitorpamplona.quartz.marmot.mls.crypto.MlsCryptoProvider
|
import com.vitorpamplona.quartz.marmot.mls.crypto.MlsCryptoProvider
|
||||||
import com.vitorpamplona.quartz.marmot.mls.crypto.X25519
|
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.nip18Reposts.quotes.quotes
|
||||||
import com.vitorpamplona.quartz.nip21UriScheme.toNostrUri
|
import com.vitorpamplona.quartz.nip21UriScheme.toNostrUri
|
||||||
import com.vitorpamplona.quartz.nip25Reactions.ReactionEvent
|
import com.vitorpamplona.quartz.nip25Reactions.ReactionEvent
|
||||||
import com.vitorpamplona.quartz.nip28PublicChat.list.ChannelListEvent
|
|
||||||
import com.vitorpamplona.quartz.nip31Alts.AltTag
|
import com.vitorpamplona.quartz.nip31Alts.AltTag
|
||||||
import com.vitorpamplona.quartz.nip50Search.SearchRelayListEvent
|
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.relayLists.RelayFeedsListEvent
|
||||||
import com.vitorpamplona.quartz.nip51Lists.tags.RelayTag
|
import com.vitorpamplona.quartz.nip51Lists.tags.RelayTag
|
||||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
|
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
|
||||||
import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent
|
|
||||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
@@ -118,7 +113,7 @@ class DatabaseNostrRepository(
|
|||||||
publicKey: HexKey,
|
publicKey: HexKey,
|
||||||
name: String?,
|
name: String?,
|
||||||
biography: String?
|
biography: String?
|
||||||
) {
|
): KeyPackageBundle {
|
||||||
val profileEventTemplate = MetadataEvent.createNew(
|
val profileEventTemplate = MetadataEvent.createNew(
|
||||||
name = name,
|
name = name,
|
||||||
about = biography,
|
about = biography,
|
||||||
@@ -213,8 +208,6 @@ class DatabaseNostrRepository(
|
|||||||
val identity = publicKey.hexToByteArray()
|
val identity = publicKey.hexToByteArray()
|
||||||
val bundle = generateKeyPackage(identity, dTag)
|
val bundle = generateKeyPackage(identity, dTag)
|
||||||
|
|
||||||
// TODO: Save the bundle?
|
|
||||||
|
|
||||||
val keyPackageBytes = bundle.keyPackage.toTlsBytes()
|
val keyPackageBytes = bundle.keyPackage.toTlsBytes()
|
||||||
val keyPackageBase64 = Base64.encode(keyPackageBytes)
|
val keyPackageBase64 = Base64.encode(keyPackageBytes)
|
||||||
val keyPackageRef = bundle.keyPackage.reference().toHexKey()
|
val keyPackageRef = bundle.keyPackage.reference().toHexKey()
|
||||||
@@ -236,6 +229,8 @@ class DatabaseNostrRepository(
|
|||||||
)
|
)
|
||||||
|
|
||||||
saveUnsignedNostrEvents(unsignedNostrEvents)
|
saveUnsignedNostrEvents(unsignedNostrEvents)
|
||||||
|
|
||||||
|
return bundle
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateKeyPackage(
|
private fun generateKeyPackage(
|
||||||
|
|||||||
@@ -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")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package at.torch.compose.repository
|
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.HexKey
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.Kind
|
import com.vitorpamplona.quartz.nip01Core.core.Kind
|
||||||
import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair
|
import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair
|
||||||
@@ -24,7 +25,7 @@ interface NostrRepository {
|
|||||||
publicKey: HexKey,
|
publicKey: HexKey,
|
||||||
name: String?,
|
name: String?,
|
||||||
biography: String?
|
biography: String?
|
||||||
)
|
): KeyPackageBundle
|
||||||
|
|
||||||
suspend fun signInToProfile(
|
suspend fun signInToProfile(
|
||||||
publicKey: HexKey
|
publicKey: HexKey
|
||||||
@@ -155,7 +156,8 @@ interface NostrRepository {
|
|||||||
publicKey: HexKey,
|
publicKey: HexKey,
|
||||||
name: String?,
|
name: String?,
|
||||||
biography: String?
|
biography: String?
|
||||||
) {
|
): KeyPackageBundle {
|
||||||
|
TODO("")
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun signInToProfile(publicKey: HexKey) {
|
override suspend fun signInToProfile(publicKey: HexKey) {
|
||||||
|
|||||||
+1
@@ -90,6 +90,7 @@ class ChatRoomCreationViewModel(
|
|||||||
viewModelScope.launch(Dispatchers.Main) {
|
viewModelScope.launch(Dispatchers.Main) {
|
||||||
if (localChatRoom != null) {
|
if (localChatRoom != null) {
|
||||||
// TODO: Broadcast the thing...
|
// TODO: Broadcast the thing...
|
||||||
|
|
||||||
// TODO: Navigate to invitation screen...
|
// TODO: Navigate to invitation screen...
|
||||||
onNavigateToChatRoom.invoke(
|
onNavigateToChatRoom.invoke(
|
||||||
ChatRoomDetailRoute(
|
ChatRoomDetailRoute(
|
||||||
|
|||||||
+15
-5
@@ -10,6 +10,7 @@ import androidx.lifecycle.viewmodel.initializer
|
|||||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||||
import at.torch.compose.ui.view.state.form.CreateProfileFormState
|
import at.torch.compose.ui.view.state.form.CreateProfileFormState
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import at.torch.compose.repository.MarmotRepository
|
||||||
import co.touchlab.kermit.Logger
|
import co.touchlab.kermit.Logger
|
||||||
import fr.acinq.bitcoin.Chain
|
import fr.acinq.bitcoin.Chain
|
||||||
import fr.acinq.bitcoin.MnemonicCode
|
import fr.acinq.bitcoin.MnemonicCode
|
||||||
@@ -18,6 +19,7 @@ import fr.acinq.lightning.Lightning
|
|||||||
import fr.acinq.lightning.crypto.LocalKeyManager
|
import fr.acinq.lightning.crypto.LocalKeyManager
|
||||||
import fr.acinq.phoenix.managers.NodeParamsManager
|
import fr.acinq.phoenix.managers.NodeParamsManager
|
||||||
import fr.acinq.phoenix.managers.nostrPublicKey
|
import fr.acinq.phoenix.managers.nostrPublicKey
|
||||||
|
import fr.acinq.phoenix.managers.nsecPassword
|
||||||
import fr.acinq.phoenix.utils.MnemonicLanguage
|
import fr.acinq.phoenix.utils.MnemonicLanguage
|
||||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -27,19 +29,22 @@ import kotlinx.coroutines.launch
|
|||||||
class CreateProfileViewModel(
|
class CreateProfileViewModel(
|
||||||
val initialCreateProfileUIState: CreateProfileUIState,
|
val initialCreateProfileUIState: CreateProfileUIState,
|
||||||
val createProfileFormState: CreateProfileFormState = CreateProfileFormState(),
|
val createProfileFormState: CreateProfileFormState = CreateProfileFormState(),
|
||||||
val nostrRepository: NostrRepository
|
val nostrRepository: NostrRepository,
|
||||||
|
val marmotRepository: MarmotRepository
|
||||||
): ViewModel() {
|
): ViewModel() {
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "CreateAccountViewModel"
|
private const val TAG = "CreateAccountViewModel"
|
||||||
|
|
||||||
fun factory(
|
fun factory(
|
||||||
initialCreateProfileUIState: CreateProfileUIState,
|
initialCreateProfileUIState: CreateProfileUIState,
|
||||||
nostrRepository: NostrRepository
|
nostrRepository: NostrRepository,
|
||||||
|
marmotRepository: MarmotRepository
|
||||||
): ViewModelProvider.Factory = viewModelFactory {
|
): ViewModelProvider.Factory = viewModelFactory {
|
||||||
initializer {
|
initializer {
|
||||||
CreateProfileViewModel(
|
CreateProfileViewModel(
|
||||||
initialCreateProfileUIState,
|
initialCreateProfileUIState,
|
||||||
nostrRepository = nostrRepository
|
nostrRepository = nostrRepository,
|
||||||
|
marmotRepository = marmotRepository
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,12 +105,17 @@ class CreateProfileViewModel(
|
|||||||
)
|
)
|
||||||
|
|
||||||
val pubkey = localKeyManager.nostrPublicKey()
|
val pubkey = localKeyManager.nostrPublicKey()
|
||||||
logger.d("NostrKey: $pubkey")
|
val keyPackageBundle = nostrRepository.createNewProfile(
|
||||||
nostrRepository.createNewProfile(
|
|
||||||
pubkey,
|
pubkey,
|
||||||
name = createProfileFormState.nameField.textFieldState.text.toString(),
|
name = createProfileFormState.nameField.textFieldState.text.toString(),
|
||||||
biography = createProfileFormState.biographyField.textFieldState.text.toString()
|
biography = createProfileFormState.biographyField.textFieldState.text.toString()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
marmotRepository.saveMarmotKeyPackageBundle(
|
||||||
|
publicKey = pubkey,
|
||||||
|
keyPackageBundle,
|
||||||
|
nsecPassword = localKeyManager.nsecPassword()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -102,6 +102,12 @@ fun LocalKeyManager.nostrPrivateKey(): PrivateKey {
|
|||||||
return derivePrivateKey(path).privateKey
|
return derivePrivateKey(path).privateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun LocalKeyManager.nsecPassword(): String {
|
||||||
|
return Crypto.hash160(
|
||||||
|
nostrPrivateKey().value
|
||||||
|
).byteVector().toHex()
|
||||||
|
}
|
||||||
|
|
||||||
fun LocalKeyManager.nostrPublicKey(): HexKey {
|
fun LocalKeyManager.nostrPublicKey(): HexKey {
|
||||||
return KeyPair(
|
return KeyPair(
|
||||||
privKey = nostrPrivateKey().value.toByteArray()
|
privKey = nostrPrivateKey().value.toByteArray()
|
||||||
|
|||||||
Reference in new issue
Block a user