Check giftWraps to us and from us...
This commit is contained in:
@@ -21,6 +21,8 @@ import ac.cord.auxiliary.compose.managers.toHex
|
||||
import androidx.room3.Dao
|
||||
import androidx.room3.Transaction
|
||||
import co.touchlab.kermit.Logger
|
||||
import com.vitorpamplona.quartz.nip01Core.core.toHexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair
|
||||
import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.events.taggedEvents
|
||||
@@ -341,198 +343,204 @@ abstract class NostrDao(
|
||||
)
|
||||
|
||||
// TODO: Might want to process this somewhere else where privateKey is available...
|
||||
SeedManager.activeKeyPair().privKey?.let { activeUserPrivateKey ->
|
||||
giftWrapMessage.decryptGiftWrapSeal(
|
||||
activeUserPrivateKey
|
||||
)?.let { giftWrapSeal ->
|
||||
database.giftWrapSealDao().upsert(
|
||||
giftWrapSeal
|
||||
)
|
||||
|
||||
giftWrapSeal.decryptGiftWrapPayload(
|
||||
if (giftWrapMessage.receiverPublicKey == SeedManager.activePublicKey().toHexKey()) {
|
||||
// This is a gift wrap message meant for us...
|
||||
SeedManager.activeKeyPair().privKey?.let { activeUserPrivateKey ->
|
||||
giftWrapMessage.decryptGiftWrapSeal(
|
||||
activeUserPrivateKey
|
||||
)?.let { decryptedGiftWrapPayload ->
|
||||
if (giftWrapSeal.publicKey.lowercase() != decryptedGiftWrapPayload.publicKey.lowercase()) {
|
||||
val giftWrapImpersonation = GiftWrapImpersonationException(
|
||||
"Seal pubkey (${giftWrapSeal.publicKey}) and payload pubkey (${decryptedGiftWrapPayload.publicKey}) needs to be the same for the giftWrap ${nostrEvent.id}"
|
||||
)
|
||||
logger.e("Impersonation", giftWrapImpersonation)
|
||||
throw giftWrapImpersonation // Once this is thrown the database transaction fails and nothing gets saved to the DB...
|
||||
}
|
||||
val result = database.giftWrapPayloadDao().upsert(
|
||||
decryptedGiftWrapPayload
|
||||
)?.let { giftWrapSeal ->
|
||||
database.giftWrapSealDao().upsert(
|
||||
giftWrapSeal
|
||||
)
|
||||
|
||||
val giftWrapPayload = if (result != -1L) {
|
||||
decryptedGiftWrapPayload.copy(
|
||||
id = result
|
||||
)
|
||||
} else {
|
||||
decryptedGiftWrapPayload
|
||||
}
|
||||
|
||||
val chatRoomId = giftWrapPayload.aggregatedParticipantsPublicKey()
|
||||
logger.d("ChatRoomId: $chatRoomId")
|
||||
|
||||
if (chatRoomId != null) {
|
||||
// Find or create chatRoom
|
||||
val localChatRoom = database.chatRoomDao().findChatRoomById(
|
||||
chatRoomId
|
||||
giftWrapSeal.decryptGiftWrapPayload(
|
||||
activeUserPrivateKey
|
||||
)?.let { decryptedGiftWrapPayload ->
|
||||
if (giftWrapSeal.publicKey.lowercase() != decryptedGiftWrapPayload.publicKey.lowercase()) {
|
||||
val giftWrapImpersonation = GiftWrapImpersonationException(
|
||||
"Seal pubkey (${giftWrapSeal.publicKey}) and payload pubkey (${decryptedGiftWrapPayload.publicKey}) needs to be the same for the giftWrap ${nostrEvent.id}"
|
||||
)
|
||||
logger.e("Impersonation", giftWrapImpersonation)
|
||||
throw giftWrapImpersonation // Once this is thrown the database transaction fails and nothing gets saved to the DB...
|
||||
}
|
||||
val result = database.giftWrapPayloadDao().upsert(
|
||||
decryptedGiftWrapPayload
|
||||
)
|
||||
|
||||
if (localChatRoom == null) {
|
||||
val userPublicKey = SeedManager.activeKeyPair().pubKey.toHex()
|
||||
database.chatRoomDao().upsert(
|
||||
ChatRoom(
|
||||
id = chatRoomId,
|
||||
userPublicKey = userPublicKey,
|
||||
subject = decryptedGiftWrapPayload.parseSubject(),
|
||||
createdAt = decryptedGiftWrapPayload.createdAt,
|
||||
initialGiftWrapPayloadId = giftWrapPayload.id
|
||||
)
|
||||
val giftWrapPayload = if (result != -1L) {
|
||||
decryptedGiftWrapPayload.copy(
|
||||
id = result
|
||||
)
|
||||
|
||||
// Add participants...
|
||||
val participants = giftWrapPayload.participantPTags(
|
||||
NormalizedRelayUrl(relayURL) // TODO: Get relayURL for publicKey profile...
|
||||
).map {
|
||||
Participant(
|
||||
participantPublicKey = it.pubKey,
|
||||
chatRoomId = chatRoomId,
|
||||
relayHint = it.relayHint?.url
|
||||
)
|
||||
}
|
||||
|
||||
// Sync missing participant profiles...
|
||||
participants.forEach { participant ->
|
||||
val giftWrapParticipantProfile = database.profileDao().getProfileByPublicKey(participant.participantPublicKey)
|
||||
|
||||
if (giftWrapParticipantProfile == null) {
|
||||
// Save a placeholder
|
||||
database.profileDao().insertPlaceholderProfile(
|
||||
Profile(
|
||||
displayName = "LOADING...",
|
||||
publicKey = participant.participantPublicKey,
|
||||
createdAt = GENESIS_AT,
|
||||
nostrEventId = nostrEvent.id, // Will get overwriting by sync,
|
||||
)
|
||||
)
|
||||
|
||||
val recommendRelayUrl = giftWrapMessage.receiverRelayHit
|
||||
|
||||
if (recommendRelayUrl != null) {
|
||||
if (profilePublicKeysToSync[recommendRelayUrl] == null) {
|
||||
profilePublicKeysToSync[recommendRelayUrl] = mutableSetOf()
|
||||
}
|
||||
profilePublicKeysToSync[recommendRelayUrl]?.add(participant.participantPublicKey)
|
||||
} else {
|
||||
if (profilePublicKeysToSync[relayURL] == null) {
|
||||
profilePublicKeysToSync[relayURL] = mutableSetOf()
|
||||
}
|
||||
profilePublicKeysToSync[relayURL]?.add(
|
||||
participant.participantPublicKey
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
database.participantDao().upsert(
|
||||
participants
|
||||
)
|
||||
|
||||
participants.filter { it.participantPublicKey != userPublicKey }.forEach { participant ->
|
||||
val publicKey = participant.participantPublicKey
|
||||
|
||||
val chatMessageRelayListEvent = database.nostrEventDao().getAuthoredNostrEvents(
|
||||
kinds = arrayOf(
|
||||
ChatMessageRelayListEvent.KIND
|
||||
),
|
||||
authors = arrayOf(
|
||||
publicKey
|
||||
),
|
||||
since = GENESIS_AT,
|
||||
limit = 5
|
||||
).firstOrNull()?.let { nostrEvent ->
|
||||
if (nostrEvent.kind != ChatMessageRelayListEvent.KIND) {
|
||||
logger.e("getAuthoredNostrEvents returned invalid ChatMessageRelayListEvent for ${publicKey}: $nostrEvent")
|
||||
null
|
||||
} else {
|
||||
ChatMessageRelayListEvent(
|
||||
id = nostrEvent.id,
|
||||
tags = nostrEvent.tags,
|
||||
pubKey = nostrEvent.pubKey,
|
||||
content = nostrEvent.content,
|
||||
createdAt = nostrEvent.createdAt.epochSeconds,
|
||||
sig = nostrEvent.sig
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (chatMessageRelayListEvent != null) {
|
||||
// Sync messages from this relay that were sent by us
|
||||
val synchronizationFilter = SynchronizationFilter(
|
||||
kinds = arrayOf(
|
||||
GiftWrapEvent.KIND,
|
||||
),
|
||||
authors = arrayOf(
|
||||
userPublicKey
|
||||
),
|
||||
tags = mapOf(
|
||||
Pair("p", listOf(participant.participantPublicKey))
|
||||
),
|
||||
limit = 50
|
||||
)
|
||||
database.negentropySynchronizeRequestDao().insert(
|
||||
chatMessageRelayListEvent.relays().map { normalizedRelayUrl ->
|
||||
NegentropySynchronizeRequest(
|
||||
id = NegentropySynchronizeRequest.computeId(
|
||||
relayURL = normalizedRelayUrl.url,
|
||||
synchronizationFilter = synchronizationFilter
|
||||
),
|
||||
purpose = "sent-messages",
|
||||
synchronizationFilter = synchronizationFilter,
|
||||
relayURL = normalizedRelayUrl.url,
|
||||
level = 0
|
||||
)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
logger.w("We don't have a chatMessageRelayListEvent for the pubkey $publicKey")
|
||||
|
||||
// Sync ChatMessageRelayListEvent publicKey...
|
||||
// TODO: Get relayHint form participant...
|
||||
if (profilePublicKeysToSync.containsKey(relayURL)) {
|
||||
profilePublicKeysToSync[relayURL] = mutableSetOf()
|
||||
}
|
||||
profilePublicKeysToSync[relayURL]?.add(participant.participantPublicKey)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
giftWrapPayload.parseSubject()?.let { subject ->
|
||||
database.chatRoomDao().upsert(
|
||||
localChatRoom.chatRoom.copy(
|
||||
subject = subject,
|
||||
updatedAt = giftWrapPayload.createdAt
|
||||
)
|
||||
)
|
||||
}
|
||||
decryptedGiftWrapPayload
|
||||
}
|
||||
|
||||
database.chatMessageDao().upsert(
|
||||
ChatMessage(
|
||||
giftWrapPayloadId = giftWrapPayload.id,
|
||||
senderPublicKey = giftWrapPayload.publicKey,
|
||||
isUserMessage = SeedManager.activePublicKey().toHex() == giftWrapPayload.publicKey,
|
||||
chatRoomId = chatRoomId,
|
||||
createdAt = giftWrapPayload.createdAt,
|
||||
content = giftWrapPayload.content,
|
||||
val chatRoomId = giftWrapPayload.aggregatedParticipantsPublicKey()
|
||||
logger.d("ChatRoomId: $chatRoomId")
|
||||
|
||||
if (chatRoomId != null) {
|
||||
// Find or create chatRoom
|
||||
val localChatRoom = database.chatRoomDao().findChatRoomById(
|
||||
chatRoomId
|
||||
)
|
||||
)
|
||||
} else {
|
||||
logger.w("Failed to setup chatRoom for message")
|
||||
|
||||
if (localChatRoom == null) {
|
||||
val userPublicKey = SeedManager.activeKeyPair().pubKey.toHex()
|
||||
database.chatRoomDao().upsert(
|
||||
ChatRoom(
|
||||
id = chatRoomId,
|
||||
userPublicKey = userPublicKey,
|
||||
subject = decryptedGiftWrapPayload.parseSubject(),
|
||||
createdAt = decryptedGiftWrapPayload.createdAt,
|
||||
initialGiftWrapPayloadId = giftWrapPayload.id
|
||||
)
|
||||
)
|
||||
|
||||
// Add participants...
|
||||
val participants = giftWrapPayload.participantPTags(
|
||||
NormalizedRelayUrl(relayURL) // TODO: Get relayURL for publicKey profile...
|
||||
).map {
|
||||
Participant(
|
||||
participantPublicKey = it.pubKey,
|
||||
chatRoomId = chatRoomId,
|
||||
relayHint = it.relayHint?.url
|
||||
)
|
||||
}
|
||||
|
||||
// Sync missing participant profiles...
|
||||
participants.forEach { participant ->
|
||||
val giftWrapParticipantProfile = database.profileDao().getProfileByPublicKey(participant.participantPublicKey)
|
||||
|
||||
if (giftWrapParticipantProfile == null) {
|
||||
// Save a placeholder
|
||||
database.profileDao().insertPlaceholderProfile(
|
||||
Profile(
|
||||
displayName = "LOADING...",
|
||||
publicKey = participant.participantPublicKey,
|
||||
createdAt = GENESIS_AT,
|
||||
nostrEventId = nostrEvent.id, // Will get overwriting by sync,
|
||||
)
|
||||
)
|
||||
|
||||
val recommendRelayUrl = giftWrapMessage.receiverRelayHit
|
||||
|
||||
if (recommendRelayUrl != null) {
|
||||
if (profilePublicKeysToSync[recommendRelayUrl] == null) {
|
||||
profilePublicKeysToSync[recommendRelayUrl] = mutableSetOf()
|
||||
}
|
||||
profilePublicKeysToSync[recommendRelayUrl]?.add(participant.participantPublicKey)
|
||||
} else {
|
||||
if (profilePublicKeysToSync[relayURL] == null) {
|
||||
profilePublicKeysToSync[relayURL] = mutableSetOf()
|
||||
}
|
||||
profilePublicKeysToSync[relayURL]?.add(
|
||||
participant.participantPublicKey
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
database.participantDao().upsert(
|
||||
participants
|
||||
)
|
||||
|
||||
participants.filter { it.participantPublicKey != userPublicKey }.forEach { participant ->
|
||||
val publicKey = participant.participantPublicKey
|
||||
|
||||
val chatMessageRelayListEvent = database.nostrEventDao().getAuthoredNostrEvents(
|
||||
kinds = arrayOf(
|
||||
ChatMessageRelayListEvent.KIND
|
||||
),
|
||||
authors = arrayOf(
|
||||
publicKey
|
||||
),
|
||||
since = GENESIS_AT,
|
||||
limit = 5
|
||||
).firstOrNull()?.let { nostrEvent ->
|
||||
if (nostrEvent.kind != ChatMessageRelayListEvent.KIND) {
|
||||
logger.e("getAuthoredNostrEvents returned invalid ChatMessageRelayListEvent for ${publicKey}: $nostrEvent")
|
||||
null
|
||||
} else {
|
||||
ChatMessageRelayListEvent(
|
||||
id = nostrEvent.id,
|
||||
tags = nostrEvent.tags,
|
||||
pubKey = nostrEvent.pubKey,
|
||||
content = nostrEvent.content,
|
||||
createdAt = nostrEvent.createdAt.epochSeconds,
|
||||
sig = nostrEvent.sig
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (chatMessageRelayListEvent != null) {
|
||||
// Sync messages from this relay that were sent by us
|
||||
val synchronizationFilter = SynchronizationFilter(
|
||||
kinds = arrayOf(
|
||||
GiftWrapEvent.KIND,
|
||||
),
|
||||
authors = arrayOf(
|
||||
userPublicKey
|
||||
),
|
||||
tags = mapOf(
|
||||
Pair("p", listOf(participant.participantPublicKey))
|
||||
),
|
||||
limit = 50
|
||||
)
|
||||
database.negentropySynchronizeRequestDao().insert(
|
||||
chatMessageRelayListEvent.relays().map { normalizedRelayUrl ->
|
||||
NegentropySynchronizeRequest(
|
||||
id = NegentropySynchronizeRequest.computeId(
|
||||
relayURL = normalizedRelayUrl.url,
|
||||
synchronizationFilter = synchronizationFilter
|
||||
),
|
||||
purpose = "sent-messages",
|
||||
synchronizationFilter = synchronizationFilter,
|
||||
relayURL = normalizedRelayUrl.url,
|
||||
level = 0
|
||||
)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
logger.w("We don't have a chatMessageRelayListEvent for the pubkey $publicKey")
|
||||
|
||||
// Sync ChatMessageRelayListEvent publicKey...
|
||||
// TODO: Get relayHint form participant...
|
||||
if (profilePublicKeysToSync.containsKey(relayURL)) {
|
||||
profilePublicKeysToSync[relayURL] = mutableSetOf()
|
||||
}
|
||||
profilePublicKeysToSync[relayURL]?.add(participant.participantPublicKey)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
giftWrapPayload.parseSubject()?.let { subject ->
|
||||
database.chatRoomDao().upsert(
|
||||
localChatRoom.chatRoom.copy(
|
||||
subject = subject,
|
||||
updatedAt = giftWrapPayload.createdAt
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
database.chatMessageDao().upsert(
|
||||
ChatMessage(
|
||||
giftWrapPayloadId = giftWrapPayload.id,
|
||||
senderPublicKey = giftWrapPayload.publicKey,
|
||||
isUserMessage = SeedManager.activePublicKey().toHex() == giftWrapPayload.publicKey,
|
||||
chatRoomId = chatRoomId,
|
||||
createdAt = giftWrapPayload.createdAt,
|
||||
content = giftWrapPayload.content,
|
||||
)
|
||||
)
|
||||
} else {
|
||||
logger.w("Failed to setup chatRoom for message")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// This may be a gift wrap message to someone we sent a message to...
|
||||
logger.w("We may have sent this message to someone")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -108,9 +108,6 @@ class ChatRoomDetailMessageListViewModel(
|
||||
kinds = arrayOf(
|
||||
GiftWrapEvent.KIND,
|
||||
),
|
||||
authors = arrayOf(
|
||||
localChatRoom.chatRoom.userPublicKey
|
||||
),
|
||||
tags = mapOf(
|
||||
Pair("p", listOf(recipients.participant.participantPublicKey))
|
||||
),
|
||||
@@ -119,6 +116,7 @@ class ChatRoomDetailMessageListViewModel(
|
||||
)
|
||||
|
||||
} else {
|
||||
// Try to find the ChatMessageRelayList for this participant...
|
||||
isReceiverChatMessageRelayListMissing.value = true
|
||||
// TODO: compute the timestamp for when list we sent messages and use that as since...
|
||||
Pair(
|
||||
@@ -135,6 +133,8 @@ class ChatRoomDetailMessageListViewModel(
|
||||
)
|
||||
}
|
||||
|
||||
logger.i("GiftWrapFilter: ${relayAndSynchronizationFilter.second}")
|
||||
|
||||
val negentropySynchronizeRequests = relayAndSynchronizationFilter.first.map { normalizedRelayUrl ->
|
||||
NegentropySynchronizeRequest(
|
||||
id = NegentropySynchronizeRequest.computeId(
|
||||
|
||||
Reference in New Issue
Block a user