diff --git a/pkg/connector/handlesignal.go b/pkg/connector/handlesignal.go index 2f6803d4..72759059 100644 --- a/pkg/connector/handlesignal.go +++ b/pkg/connector/handlesignal.go @@ -28,6 +28,7 @@ import ( "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/bridgev2/networkid" + "maunium.net/go/mautrix/bridgev2/simplevent" "maunium.net/go/mautrix/event" "go.mau.fi/mautrix-signal/pkg/signalid" @@ -40,6 +41,7 @@ func (s *SignalClient) handleSignalEvent(rawEvt events.SignalEvent) { case *events.ChatEvent: s.Main.Bridge.QueueRemoteEvent(s.UserLogin, &Bv2ChatEvent{ChatEvent: evt, s: s}) case *events.DecryptionError: + s.Main.Bridge.QueueRemoteEvent(s.UserLogin, s.wrapDecryptionError(evt)) case *events.Receipt: s.handleSignalReceipt(evt) case *events.ReadSelf: @@ -54,19 +56,22 @@ func (s *SignalClient) handleSignalEvent(rawEvt events.SignalEvent) { } func (s *SignalClient) wrapCallEvent(evt *events.Call) bridgev2.RemoteMessage { - return &bridgev2.SimpleRemoteEvent[*events.Call]{ - Type: bridgev2.RemoteEventMessage, - LogContext: func(c zerolog.Context) zerolog.Context { - c = c.Stringer("sender_id", evt.Info.Sender) - c = c.Uint64("message_ts", evt.Timestamp) - return c + return &simplevent.Message[*events.Call]{ + EventMeta: simplevent.EventMeta{ + Type: bridgev2.RemoteEventMessage, + LogContext: func(c zerolog.Context) zerolog.Context { + c = c.Stringer("sender_id", evt.Info.Sender) + c = c.Uint64("message_ts", evt.Timestamp) + return c + }, + PortalKey: s.makePortalKey(evt.Info.ChatID), + CreatePortal: true, + Sender: s.makeEventSender(evt.Info.Sender), + Timestamp: time.UnixMilli(int64(evt.Timestamp)), }, - PortalKey: s.makePortalKey(evt.Info.ChatID), - Data: evt, - CreatePortal: true, - ID: signalid.MakeMessageID(evt.Info.Sender, evt.Timestamp), - Sender: s.makeEventSender(evt.Info.Sender), - Timestamp: time.UnixMilli(int64(evt.Timestamp)), + Data: evt, + ID: signalid.MakeMessageID(evt.Info.Sender, evt.Timestamp), + ConvertMessageFunc: convertCallEvent, } } @@ -91,6 +96,38 @@ func convertCallEvent(ctx context.Context, portal *bridgev2.Portal, intent bridg }, nil } +func (s *SignalClient) wrapDecryptionError(evt *events.DecryptionError) bridgev2.RemoteMessage { + return &simplevent.Message[*events.DecryptionError]{ + EventMeta: simplevent.EventMeta{ + Type: bridgev2.RemoteEventMessage, + LogContext: func(c zerolog.Context) zerolog.Context { + c = c.Stringer("sender_id", evt.Sender) + return c + }, + PortalKey: s.makePortalKey(evt.Sender.String()), + CreatePortal: true, + Sender: s.makeEventSender(evt.Sender), + Timestamp: time.UnixMilli(int64(evt.Timestamp)), + }, + Data: evt, + ID: "decrypterr|" + signalid.MakeMessageID(evt.Sender, evt.Timestamp), + + ConvertMessageFunc: convertDecryptionError, + } +} + +func convertDecryptionError(_ context.Context, _ *bridgev2.Portal, _ bridgev2.MatrixAPI, _ *events.DecryptionError) (*bridgev2.ConvertedMessage, error) { + return &bridgev2.ConvertedMessage{ + Parts: []*bridgev2.ConvertedMessagePart{{ + Type: event.EventMessage, + Content: &event.MessageEventContent{ + MsgType: event.MsgNotice, + Body: "Message couldn't be decrypted. It may have been in this chat or a group chat. Please check your Signal app.", + }, + }}, + }, nil +} + type Bv2ChatEvent struct { *events.ChatEvent s *SignalClient diff --git a/pkg/signalmeow/events/message.go b/pkg/signalmeow/events/message.go index 0db0f247..a6fcc7f1 100644 --- a/pkg/signalmeow/events/message.go +++ b/pkg/signalmeow/events/message.go @@ -49,8 +49,9 @@ type ChatEvent struct { } type DecryptionError struct { - Sender uuid.UUID - Err error + Sender uuid.UUID + Err error + Timestamp uint64 } type Receipt struct { diff --git a/pkg/signalmeow/receiving.go b/pkg/signalmeow/receiving.go index 6f40a7f6..850e204d 100644 --- a/pkg/signalmeow/receiving.go +++ b/pkg/signalmeow/receiving.go @@ -276,6 +276,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. destinationServiceID, err := libsignalgo.ServiceIDFromString(envelope.GetDestinationServiceId()) log.Trace(). Uint64("timestamp", envelope.GetTimestamp()). + Uint64("server_timestamp", envelope.GetServerTimestamp()). Str("destination_service_id", envelope.GetDestinationServiceId()). Str("source_service_id", envelope.GetSourceServiceId()). Uint32("source_device_id", envelope.GetSourceDevice()). @@ -286,7 +287,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb. result := cli.decryptEnvelope(ctx, envelope) - err = cli.handleDecryptedResult(ctx, result, destinationServiceID) + err = cli.handleDecryptedResult(ctx, result, destinationServiceID, envelope.GetServerTimestamp()) if err != nil { log.Err(err).Msg("handleDecryptedResult error") return nil, err @@ -613,6 +614,7 @@ func (cli *Client) handleDecryptedResult( ctx context.Context, result DecryptionResult, destinationServiceID libsignalgo.ServiceID, + serverTimestamp uint64, ) error { log := zerolog.Ctx(ctx) if result.Content == nil { @@ -623,19 +625,20 @@ func (cli *Client) handleDecryptedResult( // result.Err is set if there was an error during decryption and we // should notifiy the user that the message could not be decrypted if result.Err != nil { - log.Err(result.Err).Bool("urgent", result.Urgent).Msg("Decryption error") theirServiceID, err := result.SenderAddress.NameServiceID() if err != nil { log.Err(err).Msg("Name error handling decryption error") } else if theirServiceID.Type != libsignalgo.ServiceIDTypeACI { log.Warn().Any("their_service_id", theirServiceID).Msg("Sender ServiceID is not an ACI") } + log.Err(result.Err).Stringer("sender", theirServiceID).Bool("urgent", result.Urgent).Msg("Decryption error") // Only send decryption error event if the message was urgent, // to prevent spamming errors for typing notifications and whatnot if result.Urgent { cli.handleEvent(&events.DecryptionError{ - Sender: theirServiceID.UUID, - Err: result.Err, + Sender: theirServiceID.UUID, + Err: result.Err, + Timestamp: serverTimestamp, }) } // Intentionally not returning here. In most cases there's nothing besides the error so