fix(nostr): reserve two-hour DM timestamp margin

This commit is contained in:
wollow 2026-08-11 22:37:44 +03:00
parent bc03d78972
commit acfbacf78f
4 changed files with 8 additions and 8 deletions

View File

@ -22,7 +22,7 @@ import java.math.BigInteger
*/
object NostrCrypto {
internal const val NIP17_DEFAULT_MAX_PAST_SECONDS = 85_500
internal const val NIP17_DEFAULT_MAX_PAST_SECONDS = 79_200
private val secureRandom = SecureRandom()
// NIP-44 v2 only
@ -319,7 +319,7 @@ object NostrCrypto {
}
/**
* Random timestamp in the past, defaulting to 23h45m to leave slack inside iOS's 24h lookback.
* Random timestamp in the past, defaulting to 22 hours to leave 2 hours of slack inside iOS's 24-hour lookback.
*/
fun randomizeTimestampUpToPast(maxPastSeconds: Int = NIP17_DEFAULT_MAX_PAST_SECONDS): Int {
val now = (System.currentTimeMillis() / 1000).toInt()

View File

@ -37,7 +37,7 @@ object NostrProtocol {
val rumorId = rumorBase.computeEventIdHex()
val rumor = rumorBase.copy(id = rumorId)
// 2. Seal the rumor with 15 minutes of slack inside iOS's 24-hour lookback.
// 2. Seal the rumor with 2 hours of slack inside iOS's 24-hour lookback.
val sealedEvent = createSeal(
rumor = rumor,
recipientPubkey = recipientPubkey,

View File

@ -79,7 +79,7 @@ class NostrProtocolTest {
afterCreation: Int
) {
assertTrue(
"$envelope timestamp must leave 15 minutes inside the iOS lookback",
"$envelope timestamp must leave 2 hours inside the iOS lookback",
createdAt >= beforeCreation - MAX_OUTBOUND_BACKDATE_SECONDS
)
assertTrue(
@ -132,7 +132,7 @@ class NostrProtocolTest {
private companion object {
const val IOS_DM_LOOKBACK_SECONDS = 86_400
const val TIMESTAMP_SAFETY_SLACK_SECONDS = 900
const val TIMESTAMP_SAFETY_SLACK_SECONDS = 7_200
const val MAX_OUTBOUND_BACKDATE_SECONDS =
IOS_DM_LOOKBACK_SECONDS - TIMESTAMP_SAFETY_SLACK_SECONDS
}

View File

@ -17,7 +17,7 @@ The remaining implementation work and milestone progress are tracked in
| Inner payloads | Noise type bytes, private-message TLVs, peer-state TLVs, file-transfer TLVs, live-voice bursts, fragment header, sync request TLVs | `ClientRewriteWireContractTest`, `AuthenticatedPeerStateTest`, `PrivateMediaTransferPreparerTest`, `VoiceBurstPacketTest`, `FragmentManagerTest` |
| Identity/security | Announcement extensions, capability bitfield endianness, Noise static-key binding, handshake identity binding, signatures | `IdentityAnnouncementTest`, `NoiseSessionManagerIdentityBindingTest`, `ClientRewritePrimitiveContractTest` |
| Sync/routing | Stable packet IDs, GCS bitstream, replay collapse, TTL handling, relay choice, confirmed graph edges | `ClientRewritePrimitiveContractTest`, `GCSFilterTest`, `PacketRelayManagerTest`, `MeshGraphServiceTest`, `TransportBridgeServiceTest` |
| Nostr | Bech32, secp256k1 key derivation, NIP-01 event IDs/signatures, NIP-44 authenticated encryption, NIP-13 PoW, authenticated NIP-17 seals, 23h45m outbound envelope randomization | `ClientRewriteNostrContractTest`, `NostrProtocolTest` |
| Nostr | Bech32, secp256k1 key derivation, NIP-01 event IDs/signatures, NIP-44 authenticated encryption, NIP-13 PoW, authenticated NIP-17 seals, 22h outbound envelope randomization | `ClientRewriteNostrContractTest`, `NostrProtocolTest` |
| Application state | Peer unions, canonical private conversations, chronological history, delivery/read behavior, media migration policy | `AppStateStoreTest`, `PrivateChatManagerTest`, `MediaSendingManagerMigrationTest` |
## Golden-vector policy
@ -31,9 +31,9 @@ Round-trip tests remain useful but are not sufficient on their own: an encoder
and decoder can share the same defect. Each critical wire format therefore has
at least one literal vector.
NIP-17 receivers must use a lookback at least as long as the maximum timestamp
NIP-17 receivers should reserve safety slack beyond the maximum timestamp
randomization used by senders. Android caps outbound seal and gift-wrap
randomization at 23h45m, leaving 15 minutes of slack inside iOS's 24-hour
randomization at 22h, leaving 2 hours of slack inside iOS's 24-hour
subscription window, while retaining its 48-hour receive lookback.
## Rewrite acceptance gate