fix: ask relays for gift wraps addressed to us, not to our peers
Three kind:1059 sync filters named the wrong pubkey. ChatMessageListViewModel asked for `#p:[peer]` with no author constraint, which subscribes to every wrap anyone has ever sent that peer. None of it is decryptable by us, and it is the direct source of the Invalid Mac saves fixed in the previous commit. It now asks for `#p:[us]` on our own DM relays — the only shape of gift wrap filter that can return something we hold a key for. The peer's relays were the wrong place to look regardless: under NIP-17 a sender publishes to the *recipient's* DM relays, so our mail lands on ours. The two in NostrDao asked for `authors:[userPublicKey]` + `#p:[participant]`, commented "messages from this relay that were sent by us". A gift wrap is signed by the throwaway key from GiftWrapEvent.create, never by the sender's identity key, so no author value we could know will ever match one. These requests were queued once per participant and always reconciled to empty — failing silently rather than loudly, which is why they outlived the bug that made the third filter visible. Both `if (chatMessageRelayListEvent != null)` branches held nothing else, so each is inverted to the `== null` case that does the real work: warn, and queue a profile sync for the participant whose DM relay list we are missing. Nothing is lost; neither filter ever returned an event. Two things worth recording about what a filter can and cannot express here. A wrap discloses only its recipient, so "the messages in this conversation" is not askable — `#p:[us]` pulls the whole inbox and that is the narrowest correct request. That is the privacy property being paid for, not a limitation to work around. Sent-message recovery is likewise not a filter problem. It needs a second wrap addressed to ourselves at send time, which giftWrapAndBroadcast does not yet emit; the `#p:[us]` filters already in place would pick those up with no new subscription. purpose on the chat message request changes from "sent-messages" to "chat", matching the now-identical filter in ChatRoomListViewModel. Since computeId buckets by minute and NegentropySynchronizeRequestDao upserts, the two collapse into a single request rather than racing as separate rows. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -670,41 +670,11 @@ abstract class NostrDao(
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
// Nothing to sync when we do have the relay list: a gift
|
||||
// wrap is authored by a throwaway key, so authors=us matched
|
||||
// nothing and this request was always empty. Our own inbox is
|
||||
// synced by p-tag on the chat room list instead.
|
||||
if (chatMessageRelayListEvent == null) {
|
||||
logger.w("We don't have a chatMessageRelayListEvent for the pubkey $publicKey")
|
||||
|
||||
// Sync ChatMessageRelayListEvent publicKey...
|
||||
@@ -906,35 +876,9 @@ abstract class NostrDao(
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
// See the identical block above: authors=us never matches a
|
||||
// gift wrap, so only the missing-relay-list case has work to do.
|
||||
if (chatMessageRelayListEvent == null) {
|
||||
logger.w("We don't have a chatMessageRelayListEvent for the pubkey $publicKey")
|
||||
|
||||
// Sync ChatMessageRelayListEvent publicKey...
|
||||
|
||||
@@ -123,15 +123,19 @@ class ChatMessageListViewModel(
|
||||
val chatMessageRelayListEvent = chatRepository.getChatMessageRelayForPublicKey(recipients.participant.participantPublicKey)
|
||||
|
||||
val relayAndSynchronizationFilter = if (chatMessageRelayListEvent != null) {
|
||||
// Sync messages from this relay...
|
||||
// Refresh our own inbox. A wrap names only its recipient, so
|
||||
// "the messages in this conversation" is not something a filter
|
||||
// can ask for, and the recipient's relays hold their mail, not
|
||||
// ours. p-tagging the peer here fetched other people's wraps,
|
||||
// which no key of ours can open.
|
||||
Pair(
|
||||
chatMessageRelayListEvent.relays(),
|
||||
Relays.DefaultDMRelayList,
|
||||
SynchronizationFilter(
|
||||
kinds = arrayOf(
|
||||
GiftWrapEvent.KIND,
|
||||
),
|
||||
tags = mapOf(
|
||||
Pair("p", listOf(recipients.participant.participantPublicKey))
|
||||
Pair("p", listOf(localChatRoom.chatRoom.userPublicKey))
|
||||
),
|
||||
limit = 50
|
||||
)
|
||||
@@ -166,7 +170,7 @@ class ChatMessageListViewModel(
|
||||
purpose = if (isReceiverChatMessageRelayListMissing.value) {
|
||||
"chat-message-relays"
|
||||
} else {
|
||||
"sent-messages"
|
||||
"chat"
|
||||
},
|
||||
synchronizationFilter = relayAndSynchronizationFilter.second,
|
||||
relayURL = normalizedRelayUrl.url,
|
||||
|
||||
Reference in New Issue
Block a user