mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-08-29 07:27:16 +00:00
Two re-assessment findings: - verifyScannedQR checked only staleness (now - ts > maxAge), so a future-dated timestamp bought a QR a longer validity window than a fresh one. The freshness check is now symmetric. - Inbound Nostr DMs had no client-side created_at validation; the age bound relied entirely on relays honoring the subscription's `since` filter. Both gift-wrap decrypt paths now drop rumors outside [now - lookback - skew, now + skew]. The inner rumor timestamp is the sender's true send time (only the outer gift wrap is randomized per NIP-17), so the window mirrors exactly what an honest relay already guarantees — a dishonest relay can no longer inject stale or future-dated DMs. Existing mitigations (persistent gift-wrap dedup, relay-side since) are unchanged; this closes the malicious-relay gap. Co-authored-by: jack <jackjackbits@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
33 lines
1.3 KiB
Swift
33 lines
1.3 KiB
Swift
//
|
|
// NostrInboundPipelineTimestampTests.swift
|
|
// bitchatTests
|
|
//
|
|
// This is free and unencumbered software released into the public domain.
|
|
// For more information, see <https://unlicense.org>
|
|
//
|
|
|
|
import Foundation
|
|
import Testing
|
|
@testable import bitchat
|
|
|
|
struct NostrInboundPipelineTimestampTests {
|
|
private let now = Date(timeIntervalSince1970: 1_700_000_000)
|
|
private let nowSeconds = 1_700_000_000
|
|
private let skew = Int(TransportConfig.nostrDMMaxClockSkewSeconds)
|
|
private let lookback = Int(TransportConfig.nostrDMSubscribeLookbackSeconds)
|
|
|
|
@Test("Rumor timestamps inside the lookback-plus-skew window are accepted")
|
|
func acceptsPlausibleTimestamps() {
|
|
#expect(NostrInboundPipeline.isPlausibleRumorTimestamp(nowSeconds, now: now))
|
|
#expect(NostrInboundPipeline.isPlausibleRumorTimestamp(nowSeconds - lookback + 60, now: now))
|
|
// A sender clock slightly ahead of the receiver is tolerated.
|
|
#expect(NostrInboundPipeline.isPlausibleRumorTimestamp(nowSeconds + skew - 60, now: now))
|
|
}
|
|
|
|
@Test("Future-dated and stale rumor timestamps are rejected")
|
|
func rejectsImplausibleTimestamps() {
|
|
#expect(!NostrInboundPipeline.isPlausibleRumorTimestamp(nowSeconds + skew + 60, now: now))
|
|
#expect(!NostrInboundPipeline.isPlausibleRumorTimestamp(nowSeconds - lookback - skew - 60, now: now))
|
|
}
|
|
}
|