Fix Nostr DM timestamp window for iOS

This commit is contained in:
Kane Waldo 2026-08-22 17:24:44 +07:00
parent aaac810f4f
commit 5f851b57fc
3 changed files with 31 additions and 3 deletions

View File

@ -13,6 +13,7 @@ import kotlinx.coroutines.withContext
object NostrProtocol {
private const val TAG = "NostrProtocol"
private const val NIP17_IOS_COMPATIBLE_LOOKBACK_SECONDS = 86_400
private val gson = Gson()
/**
@ -37,7 +38,8 @@ object NostrProtocol {
val rumorId = rumorBase.computeEventIdHex()
val rumor = rumorBase.copy(id = rumorId)
// 2. Seal the rumor (kind 13) signed by sender, timestamp randomized up to 2 days
// 2. Seal the rumor (kind 13) signed by sender, timestamp randomized within the
// receiver subscription window used by iOS.
val sealedEvent = createSeal(
rumor = rumor,
recipientPubkey = recipientPubkey,
@ -231,7 +233,9 @@ object NostrProtocol {
val seal = NostrEvent(
pubkey = senderPublicKey,
createdAt = NostrCrypto.randomizeTimestampUpToPast(),
createdAt = NostrCrypto.randomizeTimestampUpToPast(
NIP17_IOS_COMPATIBLE_LOOKBACK_SECONDS
),
kind = NostrKind.SEAL,
tags = emptyList(),
content = encrypted
@ -260,7 +264,9 @@ object NostrProtocol {
val giftWrap = NostrEvent(
pubkey = wrapPublicKey,
createdAt = NostrCrypto.randomizeTimestampUpToPast(),
createdAt = NostrCrypto.randomizeTimestampUpToPast(
NIP17_IOS_COMPATIBLE_LOOKBACK_SECONDS
),
kind = NostrKind.GIFT_WRAP,
tags = listOf(listOf("p", recipientPubkey)), // Tag recipient
content = encrypted

View File

@ -3,10 +3,12 @@ package com.bitchat.android.nostr
import com.google.gson.Gson
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Test
class NostrProtocolTest {
private val gson = Gson()
private val nip17IosCompatibleLookbackSeconds = 86_400
@Test
fun decryptPrivateMessage_acceptsAuthenticatedSeal() {
@ -41,6 +43,23 @@ class NostrProtocolTest {
assertNull(decrypted)
}
@Test
fun createPrivateMessage_keepsGiftWrapTimestampInsideIosLookbackWindow() {
val sender = NostrIdentity.generate()
val recipient = NostrIdentity.generate()
val before = (System.currentTimeMillis() / 1000).toInt()
val giftWrap = NostrProtocol.createPrivateMessage(
content = "bitchat1:timestamp-window",
recipientPubkey = recipient.publicKeyHex,
senderIdentity = sender
).single()
val after = (System.currentTimeMillis() / 1000).toInt()
assertTrue(giftWrap.createdAt <= after)
assertTrue(giftWrap.createdAt >= before - nip17IosCompatibleLookbackSeconds)
}
private fun forgedGiftWrap(
content: String,
claimedSender: NostrIdentity,

View File

@ -2147,6 +2147,9 @@
<artifact name="aapt2-9.3.1-15703166-osx.jar">
<sha256 value="1e35bc2ce18c3aae840be2a29659ce50d6043e907a44d98ee1cf375d044fa29c" origin="Generated by Gradle"/>
</artifact>
<artifact name="aapt2-9.3.1-15703166-windows.jar">
<sha256 value="b1006ecec7e5936257e95e97f3eba7ef439d3e44178967cc048f86c9119fb231" origin="Generated by Gradle"/>
</artifact>
<artifact name="aapt2-9.3.1-15703166.pom">
<sha256 value="edb82dcbe738ca78b31612cb307bf99e5f02f25c8125048f933e792fd7778beb" origin="Generated by Gradle"/>
</artifact>