Add signature on MarmotGroupEvent
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 1,
|
||||
"identityHash": "305e0b745bddf4352f8e34b9cbf11242",
|
||||
"identityHash": "ec367eb293e2be375d50f8d1b8133e00",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "BroadcastNostrEventReceipt",
|
||||
@@ -1252,7 +1252,7 @@
|
||||
},
|
||||
{
|
||||
"tableName": "MarmotGroupEvent",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `userPublicKey` TEXT NOT NULL, `publicKey` TEXT NOT NULL, `chatRoomId` TEXT NOT NULL, `encryptedContent` TEXT NOT NULL, `expiresAt` INTEGER, `nostrEventId` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `deletedAt` INTEGER, `broadcastedAt` INTEGER, PRIMARY KEY(`id`))",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `userPublicKey` TEXT NOT NULL, `publicKey` TEXT NOT NULL, `chatRoomId` TEXT NOT NULL, `signature` TEXT NOT NULL, `encryptedContent` TEXT NOT NULL, `expiresAt` INTEGER, `nostrEventId` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `updatedAt` INTEGER NOT NULL, `savedAt` INTEGER NOT NULL, `deletedAt` INTEGER, `broadcastedAt` INTEGER, PRIMARY KEY(`id`), FOREIGN KEY(`nostrEventId`) REFERENCES `NostrEvent`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
@@ -1278,6 +1278,12 @@
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "signature",
|
||||
"columnName": "signature",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "encryptedContent",
|
||||
"columnName": "encryptedContent",
|
||||
@@ -1329,7 +1335,20 @@
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
}
|
||||
},
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "NostrEvent",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"nostrEventId"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"id"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "MarmotInnerEvent",
|
||||
@@ -3439,7 +3458,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, '305e0b745bddf4352f8e34b9cbf11242')"
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'ec367eb293e2be375d50f8d1b8133e00')"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -391,11 +391,13 @@ abstract class MarmotOutboundDao(
|
||||
MarmotGroupEvent(
|
||||
id = groupEvent.id,
|
||||
createdAt = Instant.fromEpochSeconds(groupEvent.createdAt),
|
||||
expiresAt = groupEvent.expiration()?.let { Instant.fromEpochSeconds(it) },
|
||||
encryptedContent = groupEvent.encryptedContent(),
|
||||
chatRoomId = localChatRoom.chatRoom.id,
|
||||
nostrEventId = groupEvent.id,
|
||||
userPublicKey = groupEvent.pubKey,
|
||||
publicKey = groupEvent.pubKey
|
||||
publicKey = groupEvent.pubKey,
|
||||
signature = groupEvent.sig,
|
||||
)
|
||||
)
|
||||
database.chatMessageDao().upsert(
|
||||
|
||||
@@ -386,7 +386,8 @@ abstract class NostrDao(
|
||||
chatRoomId = chatRoomId,
|
||||
nostrEventId = nostrEvent.id,
|
||||
createdAt = Instant.fromEpochSeconds(groupEvent.createdAt),
|
||||
expiresAt = groupEvent.expiration()?.let { Instant.fromEpochSeconds(it) }
|
||||
expiresAt = groupEvent.expiration()?.let { Instant.fromEpochSeconds(it) },
|
||||
signature = groupEvent.sig
|
||||
)
|
||||
)
|
||||
MarmotInboundManager.processGroupEvent(
|
||||
|
||||
@@ -22,7 +22,12 @@ import kotlin.time.Instant
|
||||
|
||||
@Entity(
|
||||
foreignKeys = [
|
||||
|
||||
ForeignKey(
|
||||
entity = NostrEvent::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["nostrEventId"],
|
||||
onDelete = ForeignKey.CASCADE,
|
||||
),
|
||||
],
|
||||
)
|
||||
data class MarmotGroupEvent(
|
||||
@@ -38,10 +43,10 @@ data class MarmotGroupEvent(
|
||||
|
||||
val chatRoomId: String,
|
||||
|
||||
// val signature: String, // TODO: Add signature...
|
||||
val signature: String, // TODO: Add signature...
|
||||
|
||||
val encryptedContent: String,
|
||||
val expiresAt: Instant? = null,
|
||||
val expiresAt: Instant?,
|
||||
|
||||
/**
|
||||
* What gets broadcasts?
|
||||
@@ -57,69 +62,6 @@ data class MarmotGroupEvent(
|
||||
|
||||
companion object {
|
||||
const val KIND = GroupEvent.KIND
|
||||
|
||||
fun fromGroupEvent(
|
||||
groupEvent: GroupEvent,
|
||||
userPublicKey: String
|
||||
): MarmotGroupEvent? {
|
||||
return groupEvent.groupId()?.let { chatRoomId ->
|
||||
MarmotGroupEvent(
|
||||
id = groupEvent.id,
|
||||
encryptedContent = groupEvent.encryptedContent(),
|
||||
nostrEventId = groupEvent.id,
|
||||
createdAt = Instant.fromEpochSeconds(groupEvent.createdAt),
|
||||
chatRoomId = chatRoomId,
|
||||
userPublicKey = userPublicKey,
|
||||
publicKey = groupEvent.pubKey,
|
||||
expiresAt = groupEvent.expiration()?.let { Instant.fromEpochSeconds(it) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun toMarmotInnerEvent(group: MlsGroup): MarmotInnerEvent? {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt the outer ChaCha20-Poly1305 layer, trying the current epoch's
|
||||
* exporter key first and falling back to retained epoch exporter keys.
|
||||
*
|
||||
* After a commit advances the epoch, late-arriving messages encrypted
|
||||
* with the previous epoch's exporter key would fail without this fallback.
|
||||
*
|
||||
* Returns null when neither the current epoch key nor any retained key
|
||||
* decrypts. This happens normally for commits/application messages from
|
||||
* epochs that predate our join (we never held those keys), so callers
|
||||
* should treat null as an expected "nothing to do here" outcome and log
|
||||
* at DEBUG, not as an error.
|
||||
*/
|
||||
private fun tryDecryptOuterLayer(
|
||||
group: MlsGroup,
|
||||
encryptedContent: String,
|
||||
): ByteArray? {
|
||||
// Try current epoch key first
|
||||
try {
|
||||
val exporterKey = group.exporterSecret()
|
||||
return GroupEventEncryption.decrypt(encryptedContent, exporterKey)
|
||||
} catch (e: Exception) {
|
||||
// Current epoch key failed — try retained epoch keys
|
||||
Log.e("MarmotGroupEvent", "Current Epoch Key Failed", e)
|
||||
}
|
||||
|
||||
// Try retained epoch exporter keys (most recent first)
|
||||
throw MarmotMissingRetainedExporterSecretsException(
|
||||
"Torch currently doesn't support retainedExporterSecrets"
|
||||
)
|
||||
// val retainedKeys = groupManager.retainedExporterSecrets(groupId)
|
||||
// for (retainedKey in retainedKeys) {
|
||||
// try {
|
||||
// return GroupEventEncryption.decrypt(encryptedContent, retainedKey)
|
||||
// } catch (_: Exception) {
|
||||
// // This retained key didn't work — try the next one
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return null
|
||||
}
|
||||
}
|
||||
@@ -338,10 +338,10 @@ class SynchronizationViewModel(
|
||||
)
|
||||
}
|
||||
logger.d("broadcastNostrEventRequests: $broadcastNostrEventRequests")
|
||||
// Schedule broadcastNostrEventRequests
|
||||
nostrRepository.scheduleBroadcastNostrEventRequests(
|
||||
broadcastNostrEventRequests
|
||||
)
|
||||
// TODO: Schedule broadcastNostrEventRequests
|
||||
// nostrRepository.scheduleBroadcastNostrEventRequests(
|
||||
// broadcastNostrEventRequests
|
||||
// )
|
||||
|
||||
relaysSocketManager.closeNegentropySync(
|
||||
negCloseCmd,
|
||||
|
||||
Reference in New Issue
Block a user