Add MarmotRetainedEpochSecret

This commit is contained in:
Kgothatso Ngako
2026-07-06 13:52:30 +02:00
parent aaf6bbad83
commit 6b3cf4b44a
4 changed files with 162 additions and 50 deletions

View File

@@ -5,11 +5,45 @@ import androidx.room3.RoomDatabase
import androidx.room3.TypeConverters
import androidx.room3.immediateTransaction
import androidx.room3.useWriterConnection
import at.torch.compose.database.converters.TorchConverters
import at.torch.compose.database.dao.BroadcastNostrEventReceiptDao
import at.torch.compose.database.dao.BroadcastNostrEventRequestDao
import at.torch.compose.database.dao.ChatMessageBroadcastNostrEventReceiptRelationDao
import at.torch.compose.database.dao.ChatMessageBroadcastNostrEventRequestRelationDao
import at.torch.compose.database.dao.ChatMessageDao
import at.torch.compose.database.dao.ChatMessageNostrEventRelationDao
import at.torch.compose.database.dao.ChatRoomDao
import at.torch.compose.database.dao.ConnectionDao
import at.torch.compose.database.dao.GiftWrapMessageDao
import at.torch.compose.database.dao.GiftWrapPayloadDao
import at.torch.compose.database.dao.GiftWrapSealDao
import at.torch.compose.database.dao.InReplyToRelationDao
import at.torch.compose.database.dao.MarmotCommitResultDao
import at.torch.compose.database.dao.MarmotOutboundDao
import at.torch.compose.database.dao.MarmotGroupEventDao
import at.torch.compose.database.dao.MarmotInnerEventDao
import at.torch.compose.database.dao.MarmotKeyPackageBundleDao
import at.torch.compose.database.dao.MarmotKeyPackageDao
import at.torch.compose.database.dao.MarmotRetainedEpochSecretDao
import at.torch.compose.database.dao.MentionDao
import at.torch.compose.database.dao.NegentropySynchronizeRequestDao
import at.torch.compose.database.dao.NegentropySynchronizeResultDao
import at.torch.compose.database.dao.NostrDao
import at.torch.compose.database.dao.NostrEventDao
import at.torch.compose.database.dao.NostrEventRelayDao
import at.torch.compose.database.dao.NostrNip17Dao
import at.torch.compose.database.dao.ParticipantDao
import at.torch.compose.database.dao.PostDao
import at.torch.compose.database.dao.ProfileDao
import at.torch.compose.database.dao.QuotedRelationDao
import at.torch.compose.database.dao.ReactionDao
import at.torch.compose.database.dao.RecentSearchDao
import at.torch.compose.database.dao.RelayDao
import at.torch.compose.database.dao.RepostedRelationDao
import at.torch.compose.database.dao.SynchronizeNostrEventRequestDao
import at.torch.compose.database.dao.SynchronizeNostrEventResultDao
import at.torch.compose.database.dao.UnsignedNostrEventDao
import at.torch.compose.database.dao.ZapDao
import at.torch.compose.database.model.BroadcastNostrEventReceipt
import at.torch.compose.database.model.BroadcastNostrEventRequest
import at.torch.compose.database.model.ChatMessage
@@ -22,10 +56,12 @@ import at.torch.compose.database.model.GiftWrapMessage
import at.torch.compose.database.model.GiftWrapPayload
import at.torch.compose.database.model.GiftWrapSeal
import at.torch.compose.database.model.InReplyToRelation
import at.torch.compose.database.model.MarmotCommitResult
import at.torch.compose.database.model.MarmotGroupEvent
import at.torch.compose.database.model.MarmotInnerEvent
import at.torch.compose.database.model.MarmotKeyPackage
import at.torch.compose.database.model.MarmotKeyPackageBundle
import at.torch.compose.database.model.MarmotRetainedEpochSecret
import at.torch.compose.database.model.Mention
import at.torch.compose.database.model.NegentropySynchronizeRequest
import at.torch.compose.database.model.NegentropySynchronizeResult
@@ -61,10 +97,12 @@ val GENESIS_AT = Instant.fromEpochMilliseconds(1231006505000L)
GiftWrapSeal::class,
GiftWrapPayload::class,
InReplyToRelation::class,
MarmotCommitResult::class,
MarmotGroupEvent::class,
MarmotInnerEvent::class,
MarmotKeyPackage::class,
MarmotKeyPackageBundle::class,
MarmotRetainedEpochSecret::class,
Mention::class,
NegentropySynchronizeRequest::class,
NegentropySynchronizeResult::class,
@@ -85,76 +123,82 @@ val GENESIS_AT = Instant.fromEpochMilliseconds(1231006505000L)
],
version = 1
)
@TypeConverters(at.torch.compose.database.converters.TorchConverters::class)
@TypeConverters(TorchConverters::class)
abstract class TorchDatabase: RoomDatabase() {
abstract fun broadcastNostrEventReceiptDao(): at.torch.compose.database.dao.BroadcastNostrEventReceiptDao
abstract fun broadcastNostrEventRequestDao(): at.torch.compose.database.dao.BroadcastNostrEventRequestDao
abstract fun broadcastNostrEventReceiptDao(): BroadcastNostrEventReceiptDao
abstract fun broadcastNostrEventRequestDao(): BroadcastNostrEventRequestDao
abstract fun chatMessageDao(): at.torch.compose.database.dao.ChatMessageDao
abstract fun chatMessageDao(): ChatMessageDao
abstract fun chatMessageBroadcastNostrEventRequestRelationDao(): at.torch.compose.database.dao.ChatMessageBroadcastNostrEventRequestRelationDao
abstract fun chatMessageBroadcastNostrEventRequestRelationDao(): ChatMessageBroadcastNostrEventRequestRelationDao
abstract fun chatMessageBroadcastNostrEventReceiptRelationDao(): at.torch.compose.database.dao.ChatMessageBroadcastNostrEventReceiptRelationDao
abstract fun chatMessageBroadcastNostrEventReceiptRelationDao(): ChatMessageBroadcastNostrEventReceiptRelationDao
abstract fun chatMessageNostrEventRelationDao(): at.torch.compose.database.dao.ChatMessageNostrEventRelationDao
abstract fun chatMessageNostrEventRelationDao(): ChatMessageNostrEventRelationDao
abstract fun chatRoomDao(): at.torch.compose.database.dao.ChatRoomDao
abstract fun chatRoomDao(): ChatRoomDao
abstract fun connectionDao(): at.torch.compose.database.dao.ConnectionDao
abstract fun connectionDao(): ConnectionDao
abstract fun giftWrapMessageDao(): at.torch.compose.database.dao.GiftWrapMessageDao
abstract fun giftWrapMessageDao(): GiftWrapMessageDao
abstract fun giftWrapSealDao(): at.torch.compose.database.dao.GiftWrapSealDao
abstract fun giftWrapSealDao(): GiftWrapSealDao
abstract fun giftWrapPayloadDao(): at.torch.compose.database.dao.GiftWrapPayloadDao
abstract fun giftWrapPayloadDao(): GiftWrapPayloadDao
abstract fun inReplyToRelationDao(): at.torch.compose.database.dao.InReplyToRelationDao
abstract fun inReplyToRelationDao(): InReplyToRelationDao
abstract fun marmotOutboundDao(): MarmotOutboundDao
abstract fun marmotCommitResultDao(): MarmotCommitResultDao
abstract fun marmotGroupEventDao(): MarmotGroupEventDao
abstract fun marmotInnerEventDao(): MarmotInnerEventDao
abstract fun marmotKeyPackageDao(): MarmotKeyPackageDao
abstract fun marmotInnerEventDao(): MarmotInnerEventDao
abstract fun marmotKeyPackageBundleDao(): MarmotKeyPackageBundleDao
abstract fun mentionDao(): at.torch.compose.database.dao.MentionDao
abstract fun marmotKeyPackageDao(): MarmotKeyPackageDao
abstract fun negentropySynchronizeRequestDao(): at.torch.compose.database.dao.NegentropySynchronizeRequestDao
abstract fun marmotOutboundDao(): MarmotOutboundDao
abstract fun negentropySynchronizeResultDao(): at.torch.compose.database.dao.NegentropySynchronizeResultDao
abstract fun marmotRetainedEpochSecret(): MarmotRetainedEpochSecretDao
abstract fun nostrDao(): at.torch.compose.database.dao.NostrDao
abstract fun nostrEventDao(): at.torch.compose.database.dao.NostrEventDao
abstract fun mentionDao(): MentionDao
abstract fun nostrEventRelayDao(): at.torch.compose.database.dao.NostrEventRelayDao
abstract fun negentropySynchronizeRequestDao(): NegentropySynchronizeRequestDao
abstract fun nostrNip17Dao(): at.torch.compose.database.dao.NostrNip17Dao
abstract fun negentropySynchronizeResultDao(): NegentropySynchronizeResultDao
abstract fun participantDao(): at.torch.compose.database.dao.ParticipantDao
abstract fun nostrDao(): NostrDao
abstract fun postDao(): at.torch.compose.database.dao.PostDao
abstract fun nostrEventDao(): NostrEventDao
abstract fun profileDao(): at.torch.compose.database.dao.ProfileDao
abstract fun nostrEventRelayDao(): NostrEventRelayDao
abstract fun quotedRelationDao(): at.torch.compose.database.dao.QuotedRelationDao
abstract fun nostrNip17Dao(): NostrNip17Dao
abstract fun reactionDao(): at.torch.compose.database.dao.ReactionDao
abstract fun participantDao(): ParticipantDao
abstract fun recentSearchDao(): at.torch.compose.database.dao.RecentSearchDao
abstract fun postDao(): PostDao
abstract fun relayDao(): at.torch.compose.database.dao.RelayDao
abstract fun profileDao(): ProfileDao
abstract fun repostedRelationDao(): at.torch.compose.database.dao.RepostedRelationDao
abstract fun quotedRelationDao(): QuotedRelationDao
abstract fun synchronizeNostrEventRequestDao(): at.torch.compose.database.dao.SynchronizeNostrEventRequestDao
abstract fun reactionDao(): ReactionDao
abstract fun synchronizeNostrEventResultDao(): at.torch.compose.database.dao.SynchronizeNostrEventResultDao
abstract fun recentSearchDao(): RecentSearchDao
abstract fun unsignedNostrEventDao(): at.torch.compose.database.dao.UnsignedNostrEventDao
abstract fun zapDao(): at.torch.compose.database.dao.ZapDao
abstract fun relayDao(): RelayDao
abstract fun repostedRelationDao(): RepostedRelationDao
abstract fun synchronizeNostrEventRequestDao(): SynchronizeNostrEventRequestDao
abstract fun synchronizeNostrEventResultDao(): SynchronizeNostrEventResultDao
abstract fun unsignedNostrEventDao(): UnsignedNostrEventDao
abstract fun zapDao(): ZapDao
suspend fun wipeData() {
useWriterConnection { transactor ->

View File

@@ -130,6 +130,7 @@ abstract class MarmotOutboundDao(
peerKeyPackage.tlsEncodedMarmotKeyPackage
)
// pushRetainedEpoch(nostrGroupId, retainedBefore)
// persistGroup(nostrGroupId)
@@ -161,21 +162,21 @@ abstract class MarmotOutboundDao(
)
)
// TODO: Save commitResult... in case we need to broadcast welcomeEvent after relay acknowledgement...
// database.marmotCommitResultDao().upsert(
// MarmotCommitResult(
// id = commitEvent.id,
// isOneMemberInitialGroupCreation = isOneMemberInitialGroupCreation,
// chatRoomId = groupId,
// commitBytes = commitResult.commitBytes,
// preCommitExporterSecret = commitResult.preCommitExporterSecret,
// welcomeBytes = commitResult.welcomeBytes,
// framedCommitBytes = commitResult.preCommitExporterSecret,
// groupInfoBytes = commitResult.groupInfoBytes,
// userPublicKey = userPublicKey,
// createdAt = Instant.fromEpochSeconds(commitEvent.createdAt)
// )
// )
// Save commitResult... in case we need to broadcast welcomeEvent after relay acknowledgement...
database.marmotCommitResultDao().upsert(
MarmotCommitResult(
id = commitEvent.id,
isOneMemberInitialGroupCreation = isOneMemberInitialGroupCreation,
chatRoomId = groupId,
commitBytes = commitResult.commitBytes,
preCommitExporterSecret = commitResult.preCommitExporterSecret,
welcomeBytes = commitResult.welcomeBytes,
framedCommitBytes = commitResult.preCommitExporterSecret,
groupInfoBytes = commitResult.groupInfoBytes,
userPublicKey = userPublicKey,
createdAt = Instant.fromEpochSeconds(commitEvent.createdAt)
)
)
database.broadcastNostrEventRequestDao().insert(
relays.map {

View File

@@ -0,0 +1,16 @@
package at.torch.compose.database.dao
import androidx.room3.Dao
import androidx.room3.Query
import androidx.room3.Upsert
import at.torch.compose.database.model.MarmotCommitResult
import at.torch.compose.database.model.MarmotKeyPackage
import at.torch.compose.database.model.MarmotRetainedEpochSecret
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import fr.acinq.bitcoin.PublicKey
@Dao
interface MarmotRetainedEpochSecretDao {
@Upsert
suspend fun upsert(marmotRetainedEpochSecret: MarmotRetainedEpochSecret)
}

View File

@@ -0,0 +1,51 @@
package at.torch.compose.database.model
import androidx.room3.Entity
import androidx.room3.ForeignKey
@Entity(
foreignKeys = [
ForeignKey(
entity = ChatRoom::class,
parentColumns = ["id"],
childColumns = ["chatRoomId"],
onDelete = ForeignKey.CASCADE,
),
],
primaryKeys = ["chatRoomId", "epoch"]
)
data class MarmotRetainedEpochSecret(
val chatRoomId: String,
val epoch: Long,
val senderDataSecret: ByteArray, // TODO: Encrypt this...
val encryptionSecret: ByteArray, // TODO: Encrypt this...
val leafCount: Int,
val exporterSecret: ByteArray = ByteArray(0), // TODO: Encrypt this...
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
other as MarmotRetainedEpochSecret
if (epoch != other.epoch) return false
if (leafCount != other.leafCount) return false
if (chatRoomId != other.chatRoomId) return false
if (!senderDataSecret.contentEquals(other.senderDataSecret)) return false
if (!encryptionSecret.contentEquals(other.encryptionSecret)) return false
if (!exporterSecret.contentEquals(other.exporterSecret)) return false
return true
}
override fun hashCode(): Int {
var result = epoch.hashCode()
result = 31 * result + leafCount
result = 31 * result + chatRoomId.hashCode()
result = 31 * result + senderDataSecret.contentHashCode()
result = 31 * result + encryptionSecret.contentHashCode()
result = 31 * result + exporterSecret.contentHashCode()
return result
}
}