diff --git a/matrix/matrix.go b/matrix/matrix.go index 0553910..b07fa82 100644 --- a/matrix/matrix.go +++ b/matrix/matrix.go @@ -352,7 +352,7 @@ func (c *Container) OnLogin() { }) c.syncer.OnEventType(event.EventEncrypted, c.HandleEncrypted) } else { - c.syncer.OnEventType(event.EventEncrypted, c.HandleMessage) + c.syncer.OnEventType(event.EventEncrypted, c.HandleEncryptedUnsupported) } c.syncer.OnEventType(event.EventMessage, c.HandleMessage) c.syncer.OnEventType(event.EventSticker, c.HandleMessage) @@ -554,11 +554,23 @@ func (c *Container) HandleReaction(room *rooms.Room, reactsTo id.EventID, reactE } } +func (c *Container) HandleEncryptedUnsupported(source mautrix.EventSource, mxEvent *event.Event) { + mxEvent.Type = muksevt.EventEncryptionUnsupported + origContent, _ := mxEvent.Content.Parsed.(*event.EncryptedEventContent) + mxEvent.Content.Parsed = muksevt.EncryptionUnsupportedContent{Original: origContent} + c.HandleMessage(source, mxEvent) +} + func (c *Container) HandleEncrypted(source mautrix.EventSource, mxEvent *event.Event) { evt, err := c.crypto.DecryptMegolmEvent(mxEvent) if err != nil { - debug.Print("Failed to decrypt event:", err) - // TODO add decryption failed message instead of passing through directly + debug.Printf("Failed to decrypt event %s: %v", mxEvent.ID, err) + mxEvent.Type = muksevt.EventBadEncrypted + origContent, _ := mxEvent.Content.Parsed.(*event.EncryptedEventContent) + mxEvent.Content.Parsed = &muksevt.BadEncryptedContent{ + Original: origContent, + Reason: err.Error(), + } c.HandleMessage(source, mxEvent) return } @@ -987,13 +999,24 @@ func (c *Container) GetHistory(room *rooms.Room, limit int, dbPointer uint64) ([ debug.Printf("Failed to unmarshal content of event %s (type %s) by %s in %s: %v\n%s", evt.ID, evt.Type.Repr(), evt.Sender, evt.RoomID, err, string(evt.Content.VeryRaw)) } - if c.crypto != nil && evt.Type == event.EventEncrypted { - decrypted, err := c.crypto.DecryptMegolmEvent(evt) - if err != nil { - debug.Print("Failed to decrypt event:", err) - // TODO add decryption failed message instead of passing through directly + if evt.Type == event.EventEncrypted { + if c.crypto == nil { + evt.Type = muksevt.EventEncryptionUnsupported + origContent, _ := evt.Content.Parsed.(*event.EncryptedEventContent) + evt.Content.Parsed = muksevt.EncryptionUnsupportedContent{Original: origContent} } else { - resp.Chunk[i] = decrypted + decrypted, err := c.crypto.DecryptMegolmEvent(evt) + if err != nil { + debug.Printf("Failed to decrypt event %s: %v", evt.ID, err) + evt.Type = muksevt.EventBadEncrypted + origContent, _ := evt.Content.Parsed.(*event.EncryptedEventContent) + evt.Content.Parsed = &muksevt.BadEncryptedContent{ + Original: origContent, + Reason: err.Error(), + } + } else { + resp.Chunk[i] = decrypted + } } } } diff --git a/matrix/muksevt/content.go b/matrix/muksevt/content.go new file mode 100644 index 0000000..fb78323 --- /dev/null +++ b/matrix/muksevt/content.go @@ -0,0 +1,44 @@ +// gomuks - A terminal Matrix client written in Go. +// Copyright (C) 2020 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package muksevt + +import ( + "encoding/gob" + "reflect" + + "maunium.net/go/mautrix/event" +) + +var EventBadEncrypted = event.Type{Type: "net.maunium.gomuks.bad_encrypted", Class: event.MessageEventType} +var EventEncryptionUnsupported = event.Type{Type: "net.maunium.gomuks.encryption_unsupported", Class: event.MessageEventType} + +type BadEncryptedContent struct { + Original *event.EncryptedEventContent `json:"-"` + + Reason string `json:"-"` +} + +type EncryptionUnsupportedContent struct { + Original *event.EncryptedEventContent `json:"-"` +} + +func init() { + gob.Register(&BadEncryptedContent{}) + gob.Register(&EncryptionUnsupportedContent{}) + event.TypeMap[EventBadEncrypted] = reflect.TypeOf(&BadEncryptedContent{}) + event.TypeMap[EventEncryptionUnsupported] = reflect.TypeOf(&EncryptionUnsupportedContent{}) +} diff --git a/ui/messages/parser.go b/ui/messages/parser.go index 80bfa40..94c657b 100644 --- a/ui/messages/parser.go +++ b/ui/messages/parser.go @@ -81,8 +81,10 @@ func directParseEvent(matrix ifc.MatrixContainer, room *rooms.Room, evt *muksevt content.MsgType = event.MsgImage } return ParseMessage(matrix, room, evt, displayname) - case *event.EncryptedEventContent: - return NewExpandedTextMessage(evt, displayname, tstring.NewStyleTString("Decryption failed or gomuks not built with encryption support", tcell.StyleDefault.Italic(true))) + case *muksevt.BadEncryptedContent: + return NewExpandedTextMessage(evt, displayname, tstring.NewStyleTString(content.Reason, tcell.StyleDefault.Italic(true))) + case *muksevt.EncryptionUnsupportedContent: + return NewExpandedTextMessage(evt, displayname, tstring.NewStyleTString("gomuks not built with encryption support", tcell.StyleDefault.Italic(true))) case *event.TopicEventContent, *event.RoomNameEventContent, *event.CanonicalAliasEventContent: return ParseStateEvent(evt, displayname) case *event.MemberEventContent: