From b891bc7bb989875b1670cfe407a6c247d7f6feb8 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 2 Apr 2026 12:45:48 +0000 Subject: [PATCH] feat: add 20s expiration to call signaling gift wraps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All GiftWrapEvent.create() calls in WebRtcCallFactory now pass expirationDelta=20 so relays can garbage-collect the wraps after the signaling data is no longer relevant. The actual expiration timestamp is createdAt + 20s + 2 days (to account for the randomized createdAt in NIP-59 gift wraps). Previously only the inner events had expiration tags — the outer gift wraps persisted indefinitely on relays. https://claude.ai/code/session_017hZm7yu7CzmcQgZGSaqSXS --- .../quartz/nipACWebRtcCalls/WebRtcCallFactory.kt | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/WebRtcCallFactory.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/WebRtcCallFactory.kt index 74e278937..34e02aa5e 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/WebRtcCallFactory.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/WebRtcCallFactory.kt @@ -38,6 +38,10 @@ class WebRtcCallFactory { val wrap: GiftWrapEvent, ) + companion object { + const val WRAP_EXPIRATION_SECONDS = 20L + } + suspend fun createCallOffer( sdpOffer: String, calleePubKey: HexKey, @@ -47,7 +51,7 @@ class WebRtcCallFactory { ): Result { val template = CallOfferEvent.build(sdpOffer, calleePubKey, callId, callType) val signed = signer.sign(template) - val wrap = GiftWrapEvent.create(event = signed, recipientPubKey = calleePubKey) + val wrap = GiftWrapEvent.create(event = signed, recipientPubKey = calleePubKey, expirationDelta = WRAP_EXPIRATION_SECONDS) return Result(signed, wrap) } @@ -59,7 +63,7 @@ class WebRtcCallFactory { ): Result { val template = CallAnswerEvent.build(sdpAnswer, callerPubKey, callId) val signed = signer.sign(template) - val wrap = GiftWrapEvent.create(event = signed, recipientPubKey = callerPubKey) + val wrap = GiftWrapEvent.create(event = signed, recipientPubKey = callerPubKey, expirationDelta = WRAP_EXPIRATION_SECONDS) return Result(signed, wrap) } @@ -71,7 +75,7 @@ class WebRtcCallFactory { ): Result { val template = CallIceCandidateEvent.build(candidateJson, peerPubKey, callId) val signed = signer.sign(template) - val wrap = GiftWrapEvent.create(event = signed, recipientPubKey = peerPubKey) + val wrap = GiftWrapEvent.create(event = signed, recipientPubKey = peerPubKey, expirationDelta = WRAP_EXPIRATION_SECONDS) return Result(signed, wrap) } @@ -83,7 +87,7 @@ class WebRtcCallFactory { ): Result { val template = CallHangupEvent.build(peerPubKey, callId, reason) val signed = signer.sign(template) - val wrap = GiftWrapEvent.create(event = signed, recipientPubKey = peerPubKey) + val wrap = GiftWrapEvent.create(event = signed, recipientPubKey = peerPubKey, expirationDelta = WRAP_EXPIRATION_SECONDS) return Result(signed, wrap) } @@ -95,7 +99,7 @@ class WebRtcCallFactory { ): Result { val template = CallRejectEvent.build(callerPubKey, callId, reason) val signed = signer.sign(template) - val wrap = GiftWrapEvent.create(event = signed, recipientPubKey = callerPubKey) + val wrap = GiftWrapEvent.create(event = signed, recipientPubKey = callerPubKey, expirationDelta = WRAP_EXPIRATION_SECONDS) return Result(signed, wrap) } @@ -107,7 +111,7 @@ class WebRtcCallFactory { ): Result { val template = CallRenegotiateEvent.build(sdpOffer, peerPubKey, callId) val signed = signer.sign(template) - val wrap = GiftWrapEvent.create(event = signed, recipientPubKey = peerPubKey) + val wrap = GiftWrapEvent.create(event = signed, recipientPubKey = peerPubKey, expirationDelta = WRAP_EXPIRATION_SECONDS) return Result(signed, wrap) } }