diff --git a/crypto.go b/crypto.go index 3df27ce..1bc7536 100644 --- a/crypto.go +++ b/crypto.go @@ -36,6 +36,8 @@ import ( "maunium.net/go/mautrix-whatsapp/database" ) +var NoSessionFound = crypto.NoSessionFound + var levelTrace = maulogger.Level{ Name: "Trace", Severity: -10, @@ -183,6 +185,10 @@ func (helper *CryptoHelper) Encrypt(roomID id.RoomID, evtType event.Type, conten return encrypted, nil } +func (helper *CryptoHelper) WaitForSession(roomID id.RoomID, senderKey id.SenderKey, sessionID id.SessionID, timeout time.Duration) bool { + return helper.mach.WaitForSession(roomID, senderKey, sessionID, timeout) +} + func (helper *CryptoHelper) HandleMemberEvent(evt *event.Event) { helper.mach.HandleMemberEvent(evt) } diff --git a/go.mod b/go.mod index 3324082..ccc2a4b 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( gopkg.in/yaml.v2 v2.3.0 maunium.net/go/mauflag v1.0.0 maunium.net/go/maulogger/v2 v2.1.1 - maunium.net/go/mautrix v0.7.4 + maunium.net/go/mautrix v0.7.7 ) -replace github.com/Rhymen/go-whatsapp => github.com/tulir/go-whatsapp v0.3.8 +replace github.com/Rhymen/go-whatsapp => github.com/tulir/go-whatsapp v0.3.9 diff --git a/go.sum b/go.sum index d790c31..e984d5a 100644 --- a/go.sum +++ b/go.sum @@ -125,6 +125,8 @@ github.com/tulir/go-whatsapp v0.3.7 h1:6YoHsAlO+Y1SnU0bOntDmuvJQziEnBjFKO+1fOH2V github.com/tulir/go-whatsapp v0.3.7/go.mod h1:7yGOBdWidM6gsmbAFwgkwHEIhzVrm01+6UbImpMWfTM= github.com/tulir/go-whatsapp v0.3.8 h1:cRPyYhtgokUyeE2wsSlRpsw9qddi0Giun+kn9fGsl/M= github.com/tulir/go-whatsapp v0.3.8/go.mod h1:7yGOBdWidM6gsmbAFwgkwHEIhzVrm01+6UbImpMWfTM= +github.com/tulir/go-whatsapp v0.3.9 h1:fs2G8TMsSJ2y93UxM9pnFHGxMjKrdFAyavqG8MxpNQA= +github.com/tulir/go-whatsapp v0.3.9/go.mod h1:U5+sm33vrv3wz62YyRM/VS7q2ObXkxU4Xqj/3KOmN9o= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM= @@ -227,3 +229,5 @@ maunium.net/go/mautrix v0.7.2 h1:ru//jj7Y5Xj9CXBpeNyWCoxjq8iT0d+a2lNeSiN9P/o= maunium.net/go/mautrix v0.7.2/go.mod h1:Va/74MijqaS0DQ3aUqxmFO54/PMfr1LVsCOcGRHbYmo= maunium.net/go/mautrix v0.7.4 h1:MDjrvDyHcu5ozKAa80ohcXmYAXZTHgHxrhiERtvkEdY= maunium.net/go/mautrix v0.7.4/go.mod h1:Va/74MijqaS0DQ3aUqxmFO54/PMfr1LVsCOcGRHbYmo= +maunium.net/go/mautrix v0.7.7 h1:yfpTizagog8NRHcMjxkCyY7Vreb0OEXaessaJBaLQrw= +maunium.net/go/mautrix v0.7.7/go.mod h1:FpsAvwNdG3Zeup7Y2Nlv81Lk0h6iVRPoIy6D7g/7YCE= diff --git a/main.go b/main.go index e769ac5..a4582cf 100644 --- a/main.go +++ b/main.go @@ -44,7 +44,7 @@ var ( Name = "mautrix-whatsapp" URL = "https://github.com/tulir/mautrix-whatsapp" // This is changed when making a release - Version = "0.1.4" + Version = "0.1.4" // This is filled by init() WAVersion = "" // These are filled at build time with the -X linker flag @@ -134,7 +134,7 @@ type Bridge struct { Formatter *Formatter Relaybot *User Crypto Crypto - Metrics *MetricsHandler + Metrics *MetricsHandler usersByMXID map[id.UserID]*User usersByJID map[types.WhatsAppID]*User @@ -153,6 +153,7 @@ type Crypto interface { HandleMemberEvent(*event.Event) Decrypt(*event.Event) (*event.Event, error) Encrypt(id.RoomID, event.Type, event.Content) (*event.EncryptedEventContent, error) + WaitForSession(id.RoomID, id.SenderKey, id.SessionID, time.Duration) bool Init() error Start() Stop() diff --git a/matrix.go b/matrix.go index f4f269f..8e0f6bd 100644 --- a/matrix.go +++ b/matrix.go @@ -17,12 +17,14 @@ package main import ( + "errors" "fmt" "strings" + "time" "maunium.net/go/maulogger/v2" - "maunium.net/go/mautrix" + "maunium.net/go/mautrix" "maunium.net/go/mautrix/appservice" "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/format" @@ -330,6 +332,8 @@ func (mx *MatrixHandler) shouldIgnoreEvent(evt *event.Event) bool { return false } +const sessionWaitTimeout = 3 * time.Second + func (mx *MatrixHandler) HandleEncrypted(evt *event.Event) { defer mx.bridge.Metrics.TrackEvent(evt.Type)() if mx.shouldIgnoreEvent(evt) || mx.bridge.Crypto == nil { @@ -337,10 +341,17 @@ func (mx *MatrixHandler) HandleEncrypted(evt *event.Event) { } decrypted, err := mx.bridge.Crypto.Decrypt(evt) + if err != nil { + content := evt.Content.AsEncrypted() + if errors.Is(err, NoSessionFound) && mx.bridge.Crypto.WaitForSession(evt.RoomID, content.SenderKey, content.SessionID, sessionWaitTimeout) { + mx.log.Debugfln("Got session %s to decrypt %s after waiting a while, trying to decrypt again", evt.ID, content.SessionID) + decrypted, err = mx.bridge.Crypto.Decrypt(evt) + } + } if err != nil { mx.log.Warnfln("Failed to decrypt %s: %v", evt.ID, err) _, _ = mx.bridge.Bot.SendNotice(evt.RoomID, fmt.Sprintf( - "\u26a0 Your message was not bridged: %v. " + + "\u26a0 Your message was not bridged: %v. "+ "Try restarting your client if this error keeps happening.", err)) return } diff --git a/no-crypto.go b/no-crypto.go index a339a0a..3789a10 100644 --- a/no-crypto.go +++ b/no-crypto.go @@ -9,3 +9,5 @@ func NewCryptoHelper(bridge *Bridge) Crypto { bridge.Log.Debugln("Bridge built without end-to-bridge encryption") return nil } + +var NoSessionFound = errors.New("nil") diff --git a/portal.go b/portal.go index aa082e7..2582248 100644 --- a/portal.go +++ b/portal.go @@ -1129,7 +1129,7 @@ func (portal *Portal) HandleMessageRevoke(user *User, message whatsappExt.Messag msg.Delete() } -func (portal *Portal) HandleFakeMessage(source *User, message FakeMessage) { +func (portal *Portal) HandleFakeMessage(_ *User, message FakeMessage) { if portal.isRecentlyHandled(message.ID) { return } @@ -1465,9 +1465,10 @@ func (portal *Portal) HandleMediaMessage(source *User, msg mediaMessage) { uploaded, err := intent.UploadBytes(data, uploadMimeType) if err != nil { - httpErr := err.(mautrix.HTTPError) - if httpErr.Code == 413 { - portal.sendMediaBridgeFailure(source, intent, msg.info, errors.New("server rejected too large file")) + if errors.Is(err, mautrix.MTooLarge) { + portal.sendMediaBridgeFailure(source, intent, msg.info, errors.New("homeserver rejected too large file")) + } else if httpErr := err.(mautrix.HTTPError); httpErr.IsStatus(413) { + portal.sendMediaBridgeFailure(source, intent, msg.info, errors.New("proxy rejected too large file")) } else { portal.sendMediaBridgeFailure(source, intent, msg.info, errors.Wrap(err, "failed to upload media")) } @@ -2100,7 +2101,7 @@ func (portal *Portal) Cleanup(puppetsOnly bool) { portal.log.Errorln("Failed to get portal members for cleanup:", err) return } - for member, _ := range members.Joined { + for member := range members.Joined { if member == intent.UserID { continue } diff --git a/user.go b/user.go index 5ea2a6f..35e8a88 100644 --- a/user.go +++ b/user.go @@ -18,6 +18,7 @@ package main import ( "encoding/json" + "errors" "fmt" "net/http" "sort" @@ -26,7 +27,6 @@ import ( "sync" "time" - "github.com/pkg/errors" "github.com/skip2/go-qrcode" log "maunium.net/go/maulogger/v2" @@ -683,7 +683,7 @@ func (user *User) updateLastConnectionIfNecessary() { } func (user *User) HandleError(err error) { - if errors.Cause(err) != whatsapp.ErrInvalidWsData { + if !errors.Is(err, whatsapp.ErrInvalidWsData) { user.log.Errorfln("WhatsApp error: %v", err) } if closed, ok := err.(*whatsapp.ErrConnectionClosed); ok {