From c3a422347ce3da25637a6f1239e676db530df01d Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 25 Aug 2025 18:36:03 +0300 Subject: [PATCH] bridgev2/portal: validate capabilities when updating disappearing timer --- bridgev2/errors.go | 2 ++ bridgev2/portal.go | 7 +++++++ event/capabilities.go | 7 +++++++ 3 files changed, 16 insertions(+) diff --git a/bridgev2/errors.go b/bridgev2/errors.go index c023dcdf..026a95f4 100644 --- a/bridgev2/errors.go +++ b/bridgev2/errors.go @@ -67,6 +67,8 @@ var ( ErrPowerLevelsNotSupported error = WrapErrorInStatus(errors.New("this bridge does not support changing group power levels")).WithIsCertain(true).WithErrorAsMessage().WithSendNotice(false) ErrRemoteEchoTimeout = WrapErrorInStatus(errors.New("remote echo timed out")).WithIsCertain(false).WithSendNotice(true).WithErrorReason(event.MessageStatusTooOld) ErrRemoteAckTimeout = WrapErrorInStatus(errors.New("remote ack timed out")).WithIsCertain(false).WithSendNotice(true).WithErrorReason(event.MessageStatusTooOld) + + ErrDisappearingTimerUnsupported error = WrapErrorInStatus(errors.New("invalid disappearing timer")).WithIsCertain(true) ) // Common login interface errors diff --git a/bridgev2/portal.go b/bridgev2/portal.go index 24365df9..5e0a9137 100644 --- a/bridgev2/portal.go +++ b/bridgev2/portal.go @@ -1488,6 +1488,10 @@ func handleMatrixRoomMeta[APIType any, ContentType any]( portal.sendSuccessStatus(ctx, evt, 0, "") return EventHandlingResultIgnored } + if !sender.Client.GetCapabilities(ctx, portal).DisappearingTimer.Supports(typedContent) { + portal.sendRoomMeta(ctx, nil, time.Now(), event.StateBeeperDisappearingTimer, "", portal.Disappear.ToEventContent()) + return EventHandlingResultFailed.WithMSSError(ErrDisappearingTimerUnsupported) + } } var prevContent ContentType if evt.Unsigned.PrevContent != nil { @@ -1508,6 +1512,9 @@ func handleMatrixRoomMeta[APIType any, ContentType any]( }) if err != nil { log.Err(err).Msg("Failed to handle Matrix room metadata") + if evt.Type == event.StateBeeperDisappearingTimer { + portal.sendRoomMeta(ctx, nil, time.Now(), event.StateBeeperDisappearingTimer, "", portal.Disappear.ToEventContent()) + } return EventHandlingResultFailed.WithMSSError(err) } if changed { diff --git a/event/capabilities.go b/event/capabilities.go index f44d6600..20f87bce 100644 --- a/event/capabilities.go +++ b/event/capabilities.go @@ -76,6 +76,13 @@ type DisappearingTimerCapability struct { OmitEmptyTimer bool `json:"omit_empty_timer,omitempty"` } +func (dtc *DisappearingTimerCapability) Supports(content *BeeperDisappearingTimer) bool { + if dtc == nil || content.Type == DisappearingTypeNone { + return true + } + return slices.Contains(dtc.Types, content.Type) && slices.Contains(dtc.Timers, content.Timer) +} + type CapabilityMsgType = MessageType // Message types which are used for event capability signaling, but aren't real values for the msgtype field.