From 5bf083832995f8b8df0b1df849f207ec29527fea Mon Sep 17 00:00:00 2001 From: zhaoYangguang <1163765691@qq.com> Date: Fri, 27 Nov 2020 11:10:19 +0800 Subject: [PATCH 01/11] change device name --- community.go | 2 +- crypto.go | 4 ++-- custompuppet.go | 4 ++-- user.go | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/community.go b/community.go index 849fbca..4544a66 100644 --- a/community.go +++ b/community.go @@ -22,7 +22,7 @@ func (user *User) updateCommunityProfile() { Name string `json:"name"` AvatarURL string `json:"avatar_url"` ShortDescription string `json:"short_description"` - }{"WhatsApp", user.bridge.Config.AppService.Bot.Avatar, "Your WhatsApp bridged chats"} + }{"Skype", user.bridge.Config.AppService.Bot.Avatar, "Your Skype bridged chats"} _, err := user.bridge.Bot.MakeRequest(http.MethodPost, url, &profileReq, nil) if err != nil { user.log.Warnfln("Failed to update metadata of %s: %v", user.CommunityID, err) diff --git a/crypto.go b/crypto.go index 709325e..f67db9a 100644 --- a/crypto.go +++ b/crypto.go @@ -138,7 +138,7 @@ func (helper *CryptoHelper) loginBot() (*mautrix.Client, error) { Type: mautrix.AuthTypeAppservice, Identifier: mautrix.UserIdentifier{Type: mautrix.IdentifierTypeUser, User: string(helper.bridge.AS.BotMXID())}, DeviceID: deviceID, - InitialDeviceDisplayName: "WhatsApp Bridge", + InitialDeviceDisplayName: "Skype Bridge", StoreCredentials: true, }) if err != nil { @@ -166,7 +166,7 @@ func (helper *CryptoHelper) loginBotOld() (*mautrix.Client, error) { Identifier: mautrix.UserIdentifier{Type: mautrix.IdentifierTypeUser, User: string(helper.bridge.AS.BotMXID())}, Password: hex.EncodeToString(mac.Sum(nil)), DeviceID: deviceID, - InitialDeviceDisplayName: "WhatsApp Bridge", + InitialDeviceDisplayName: "Skype Bridge", StoreCredentials: true, }) if err != nil { diff --git a/custompuppet.go b/custompuppet.go index 91ea32c..58cab5c 100644 --- a/custompuppet.go +++ b/custompuppet.go @@ -51,8 +51,8 @@ func (puppet *Puppet) loginWithSharedSecret(mxid id.UserID) (string, error) { Type: "m.login.password", Identifier: mautrix.UserIdentifier{Type: "m.id.user", User: string(mxid)}, Password: hex.EncodeToString(mac.Sum(nil)), - DeviceID: "WhatsApp Bridge", - InitialDeviceDisplayName: "WhatsApp Bridge", + DeviceID: "Skype Bridge", + InitialDeviceDisplayName: "Skype Bridge", }) if err != nil { return "", err diff --git a/user.go b/user.go index f567ffe..89bed9d 100644 --- a/user.go +++ b/user.go @@ -183,7 +183,7 @@ func (user *User) GetManagementRoom() id.RoomID { return user.ManagementRoom } resp, err := user.bridge.Bot.CreateRoom(&mautrix.ReqCreateRoom{ - Topic: "WhatsApp bridge notices", + Topic: "Skype bridge notices", IsDirect: true, }) if err != nil { From b2471e801f8e0ca9650eadfe010e39bbeeb4e951 Mon Sep 17 00:00:00 2001 From: zhaoYangguang <1163765691@qq.com> Date: Fri, 27 Nov 2020 12:17:47 +0800 Subject: [PATCH 02/11] Remove irrelevant code --- commands.go | 14 +- go.mod | 3 - portal.go | 379 +++++++++-------------------------- puppet.go | 10 +- skype-ext/chat.go | 5 +- skype-ext/cmd.go | 5 +- user.go | 242 +++++++++++----------- whatsapp-ext/call.go | 72 ------- whatsapp-ext/chat.go | 174 ---------------- whatsapp-ext/cmd.go | 69 ------- whatsapp-ext/conn.go | 65 ------ whatsapp-ext/jsonmessage.go | 105 ---------- whatsapp-ext/msginfo.go | 95 --------- whatsapp-ext/presence.go | 67 ------- whatsapp-ext/props.go | 73 ------- whatsapp-ext/protomessage.go | 59 ------ whatsapp-ext/stream.go | 68 ------- whatsapp-ext/whatsapp.go | 206 ------------------- 18 files changed, 224 insertions(+), 1487 deletions(-) delete mode 100644 whatsapp-ext/call.go delete mode 100644 whatsapp-ext/chat.go delete mode 100644 whatsapp-ext/cmd.go delete mode 100644 whatsapp-ext/conn.go delete mode 100644 whatsapp-ext/jsonmessage.go delete mode 100644 whatsapp-ext/msginfo.go delete mode 100644 whatsapp-ext/presence.go delete mode 100644 whatsapp-ext/props.go delete mode 100644 whatsapp-ext/protomessage.go delete mode 100644 whatsapp-ext/stream.go delete mode 100644 whatsapp-ext/whatsapp.go diff --git a/commands.go b/commands.go index 72e7b93..2df83ca 100644 --- a/commands.go +++ b/commands.go @@ -8,11 +8,9 @@ import ( "math" "time" - //"math" "sort" "strconv" "strings" - //"time" "maunium.net/go/maulogger/v2" @@ -21,8 +19,6 @@ import ( "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/format" "maunium.net/go/mautrix/id" - - "github.com/kelaresg/matrix-skype/whatsapp-ext" ) type CommandHandler struct { @@ -697,7 +693,7 @@ func (handler *CommandHandler) CommandOpen(ce *CommandEvent) { jid := ce.Args[0] if strings.HasSuffix(jid, skypeExt.NewUserSuffix) { - ce.Reply("That looks like a user ID. Did you mean `pm %s`?", jid[:len(jid)-len(whatsappExt.NewUserSuffix)]) + ce.Reply("That looks like a user ID. Did you mean `pm %s`?", jid[:len(jid)-len(skypeExt.NewUserSuffix)]) return } ce.User.Conn.GetConversations("", handler.bridge.Config.Bridge.InitialChatSync) @@ -977,7 +973,7 @@ func (handler *CommandHandler) CommandKick(ce *CommandEvent) { // reason = ce.Args[0] //} - if strings.HasSuffix(converationId, whatsappExt.NewUserSuffix) { + if strings.HasSuffix(converationId, skypeExt.NewUserSuffix) { ce.Reply("**Usage:** `kick ,... reason`") return } @@ -995,8 +991,8 @@ func (handler *CommandHandler) CommandKick(ce *CommandEvent) { portal := user.bridge.GetPortalByJID(database.GroupPortalKey(converationId)) for i, number := range userNumbers { - userNumbers[i] = number // + whatsappExt.NewUserSuffix - member := portal.bridge.GetPuppetByJID(number + whatsappExt.NewUserSuffix) + userNumbers[i] = number // + skypeExt.NewUserSuffix + member := portal.bridge.GetPuppetByJID(number + skypeExt.NewUserSuffix) if member == nil { portal.log.Errorln("%s is not a puppet", number) @@ -1025,7 +1021,7 @@ func (handler *CommandHandler) CommandLeave(ce *CommandEvent) { user := ce.User groupId := ce.Args[0] - if strings.HasSuffix(groupId, whatsappExt.NewUserSuffix) { + if strings.HasSuffix(groupId, skypeExt.NewUserSuffix) { ce.Reply("**Usage:** `leave `") return } diff --git a/go.mod b/go.mod index d59b3e1..ac80bb8 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,6 @@ module github.com/kelaresg/matrix-skype go 1.14 require ( - github.com/Rhymen/go-whatsapp v0.1.0 github.com/chai2010/webp v1.1.0 github.com/gorilla/websocket v1.4.2 github.com/kelaresg/go-skypeapi v0.1.2-0.20201126103218-226d1ec92858 @@ -19,6 +18,4 @@ require ( maunium.net/go/mautrix v0.8.0-rc.4 ) -replace github.com/Rhymen/go-whatsapp => github.com/tulir/go-whatsapp v0.2.8 - replace maunium.net/go/mautrix => github.com/pidongqianqian/mautrix-go v0.8.0-rc.4.0.20201126070406-7b13ac473bcc diff --git a/portal.go b/portal.go index d1dfedc..d818c28 100644 --- a/portal.go +++ b/portal.go @@ -2,13 +2,16 @@ package main import ( "bytes" - "encoding/gob" + //whatsappExt "github.com/kelaresg/matrix-skype/whatsapp-ext" + + //"encoding/gob" "encoding/hex" "encoding/json" "encoding/xml" "fmt" skype "github.com/kelaresg/go-skypeapi" skypeExt "github.com/kelaresg/matrix-skype/skype-ext" + //whatsappExt "github.com/kelaresg/matrix-skype/whatsapp-ext" "html" "image" "image/gif" @@ -28,8 +31,8 @@ import ( "maunium.net/go/mautrix/crypto/attachment" - "github.com/Rhymen/go-whatsapp" - waProto "github.com/Rhymen/go-whatsapp/binary/proto" + //"github.com/Rhymen/go-whatsapp" + //waProto "github.com/Rhymen/go-whatsapp/binary/proto" "maunium.net/go/mautrix" "maunium.net/go/mautrix/appservice" @@ -40,7 +43,7 @@ import ( "github.com/kelaresg/matrix-skype/database" "github.com/kelaresg/matrix-skype/types" - "github.com/kelaresg/matrix-skype/whatsapp-ext" + //"github.com/kelaresg/matrix-skype/whatsapp-ext" ) func (bridge *Bridge) GetPortalByMXID(mxid id.RoomID) *Portal { @@ -251,36 +254,36 @@ func (portal *Portal) isDuplicate(clientMessageId types.SkypeMessageID, id strin return false } -func init() { - gob.Register(&waProto.Message{}) -} +//func init() { +// gob.Register(&waProto.Message{}) +//} -func (portal *Portal) markHandled(source *User, message *waProto.WebMessageInfo, mxid id.EventID) { - msg := portal.bridge.DB.Message.New() - msg.Chat = portal.Key - msg.JID = message.GetKey().GetId() - msg.MXID = mxid - msg.Timestamp = message.GetMessageTimestamp() - if message.GetKey().GetFromMe() { - msg.Sender = source.JID - } else if portal.IsPrivateChat() { - msg.Sender = portal.Key.JID - } else { - msg.Sender = message.GetKey().GetParticipant() - if len(msg.Sender) == 0 { - msg.Sender = message.GetParticipant() - } - } - //msg.Content = message.Message - msg.Content = &skype.Resource{} - msg.Insert() - - portal.recentlyHandledLock.Lock() - index := portal.recentlyHandledIndex - portal.recentlyHandledIndex = (portal.recentlyHandledIndex + 1) % recentlyHandledLength - portal.recentlyHandledLock.Unlock() - portal.recentlyHandled[index] = msg.JID -} +//func (portal *Portal) markHandled(source *User, message *waProto.WebMessageInfo, mxid id.EventID) { +// msg := portal.bridge.DB.Message.New() +// msg.Chat = portal.Key +// msg.JID = message.GetKey().GetId() +// msg.MXID = mxid +// msg.Timestamp = message.GetMessageTimestamp() +// if message.GetKey().GetFromMe() { +// msg.Sender = source.JID +// } else if portal.IsPrivateChat() { +// msg.Sender = portal.Key.JID +// } else { +// msg.Sender = message.GetKey().GetParticipant() +// if len(msg.Sender) == 0 { +// msg.Sender = message.GetParticipant() +// } +// } +// //msg.Content = message.Message +// msg.Content = &skype.Resource{} +// msg.Insert() +// +// portal.recentlyHandledLock.Lock() +// index := portal.recentlyHandledIndex +// portal.recentlyHandledIndex = (portal.recentlyHandledIndex + 1) % recentlyHandledLength +// portal.recentlyHandledLock.Unlock() +// portal.recentlyHandled[index] = msg.JID +//} func (portal *Portal) markHandledSkype(source *User, message *skype.Resource, mxid id.EventID) { msg := portal.bridge.DB.Message.New() @@ -312,20 +315,20 @@ fmt.Println("markHandledSkype2", msg.JID) portal.recentlyHandled[index] = msg.JID } -func (portal *Portal) getMessageIntent(user *User, info whatsapp.MessageInfo) *appservice.IntentAPI { - if info.FromMe { - return portal.bridge.GetPuppetByJID(user.JID).IntentFor(portal) - } else if portal.IsPrivateChat() { - return portal.MainIntent() - } else if len(info.SenderJid) == 0 { - if len(info.Source.GetParticipant()) != 0 { - info.SenderJid = info.Source.GetParticipant() - } else { - return nil - } - } - return portal.bridge.GetPuppetByJID(info.SenderJid).IntentFor(portal) -} +//func (portal *Portal) getMessageIntent(user *User, info whatsapp.MessageInfo) *appservice.IntentAPI { +// if info.FromMe { +// return portal.bridge.GetPuppetByJID(user.JID).IntentFor(portal) +// } else if portal.IsPrivateChat() { +// return portal.MainIntent() +// } else if len(info.SenderJid) == 0 { +// if len(info.Source.GetParticipant()) != 0 { +// info.SenderJid = info.Source.GetParticipant() +// } else { +// return nil +// } +// } +// return portal.bridge.GetPuppetByJID(info.SenderJid).IntentFor(portal) +//} func (portal *Portal) getMessageIntentSkype(user *User, info skype.Resource) *appservice.IntentAPI { if info.GetFromMe(user.Conn.Conn) { @@ -385,11 +388,11 @@ func (portal *Portal) startHandlingSkype(source *User, info skype.Resource) (*ap return nil, nil } -func (portal *Portal) finishHandling(source *User, message *waProto.WebMessageInfo, mxid id.EventID) { - portal.markHandled(source, message, mxid) - portal.sendDeliveryReceipt(mxid) - portal.log.Debugln("Handled message", message.GetKey().GetId(), "->", mxid) -} +//func (portal *Portal) finishHandling(source *User, message *waProto.WebMessageInfo, mxid id.EventID) { +// portal.markHandled(source, message, mxid) +// portal.sendDeliveryReceipt(mxid) +// portal.log.Debugln("Handled message", message.GetKey().GetId(), "->", mxid) +//} func (portal *Portal) finishHandlingSkype(source *User, message *skype.Resource, mxid id.EventID) { portal.markHandledSkype(source, message, mxid) @@ -1291,21 +1294,21 @@ func (portal *Portal) MainIntent() *appservice.IntentAPI { return portal.bridge.Bot } -func (portal *Portal) SetReply(content *event.MessageEventContent, info whatsapp.ContextInfo) { - if len(info.QuotedMessageID) == 0 { - return - } - message := portal.bridge.DB.Message.GetByJID(portal.Key, info.QuotedMessageID) - if message != nil { - evt, err := portal.MainIntent().GetEvent(portal.MXID, message.MXID) - if err != nil { - portal.log.Warnln("Failed to get reply target:", err) - return - } - content.SetReply(evt) - } - return -} +//func (portal *Portal) SetReply(content *event.MessageEventContent, info whatsapp.ContextInfo) { +// if len(info.QuotedMessageID) == 0 { +// return +// } +// message := portal.bridge.DB.Message.GetByJID(portal.Key, info.QuotedMessageID) +// if message != nil { +// evt, err := portal.MainIntent().GetEvent(portal.MXID, message.MXID) +// if err != nil { +// portal.log.Warnln("Failed to get reply target:", err) +// return +// } +// content.SetReply(evt) +// } +// return +//} func (portal *Portal) SetReplySkype(content *event.MessageEventContent, info skype.Resource) { if len(info.Id) == 0 { @@ -1347,32 +1350,31 @@ func (portal *Portal) HandleMessageRevokeSkype(user *User, message skype.Resourc msg.Delete() } - -func (portal *Portal) HandleMessageRevoke(user *User, message whatsappExt.MessageRevocation) { - msg := portal.bridge.DB.Message.GetByJID(portal.Key, message.Id) - if msg == nil { - return - } - var intent *appservice.IntentAPI - if message.FromMe { - if portal.IsPrivateChat() { - intent = portal.bridge.GetPuppetByJID(user.JID).CustomIntent() - } else { - intent = portal.bridge.GetPuppetByJID(user.JID).IntentFor(portal) - } - } else if len(message.Participant) > 0 { - intent = portal.bridge.GetPuppetByJID(message.Participant).IntentFor(portal) - } - if intent == nil { - intent = portal.MainIntent() - } - _, err := intent.RedactEvent(portal.MXID, msg.MXID) - if err != nil { - portal.log.Errorln("Failed to redact %s: %v", msg.JID, err) - return - } - msg.Delete() -} +//func (portal *Portal) HandleMessageRevoke(user *User, message whatsappExt.MessageRevocation) { +// msg := portal.bridge.DB.Message.GetByJID(portal.Key, message.Id) +// if msg == nil { +// return +// } +// var intent *appservice.IntentAPI +// if message.FromMe { +// if portal.IsPrivateChat() { +// intent = portal.bridge.GetPuppetByJID(user.JID).CustomIntent() +// } else { +// intent = portal.bridge.GetPuppetByJID(user.JID).IntentFor(portal) +// } +// } else if len(message.Participant) > 0 { +// intent = portal.bridge.GetPuppetByJID(message.Participant).IntentFor(portal) +// } +// if intent == nil { +// intent = portal.MainIntent() +// } +// _, err := intent.RedactEvent(portal.MXID, msg.MXID) +// if err != nil { +// portal.log.Errorln("Failed to redact %s: %v", msg.JID, err) +// return +// } +// msg.Delete() +//} func (portal *Portal) HandleFakeMessage(source *User, message FakeMessage) { if portal.isRecentlyHandled(message.ID) { @@ -1579,7 +1581,7 @@ func (portal *Portal) HandleMediaMessageSkype(source *User, download func(conn * } data, mediaMessage, err := download(source.Conn.Conn, mediaType) - if err == whatsapp.ErrMediaDownloadFailedWith404 || err == whatsapp.ErrMediaDownloadFailedWith410 { + if err == skype.ErrMediaDownloadFailedWith404 || err == skype.ErrMediaDownloadFailedWith410 { portal.log.Warnfln("Failed to download media for %s: %v. Calling LoadMediaInfo and retrying download...", info.Id, err) //_, err = source.Conn.LoadMediaInfo(info.RemoteJid, info.Id, info.FromMe) //if err != nil { @@ -1588,7 +1590,7 @@ func (portal *Portal) HandleMediaMessageSkype(source *User, download func(conn * //} data, mediaMessage, err = download(source.Conn.Conn, mediaType) } - if err == whatsapp.ErrNoURLPresent { + if err == skype.ErrNoURLPresent { portal.log.Debugfln("No URL present error for media message %s, ignoring...", info.Id) return } else if err != nil { @@ -1819,54 +1821,6 @@ func (portal *Portal) preprocessMatrixMediaSkype(relaybotFormatted bool, content return caption, uint64(len(data)), data } -func (portal *Portal) preprocessMatrixMedia(sender *User, relaybotFormatted bool, content *event.MessageEventContent, eventID id.EventID, mediaType whatsapp.MediaType) *MediaUpload { - //var caption string - //if relaybotFormatted { - // caption = portal.bridge.Formatter.ParseMatrix(content.FormattedBody) - //} - - var file *event.EncryptedFileInfo - rawMXC := content.URL - if content.File != nil { - file = content.File - rawMXC = file.URL - } - mxc, err := rawMXC.Parse() - if err != nil { - portal.log.Errorln("Malformed content URL in %s: %v", eventID, err) - return nil - } - data, err := portal.MainIntent().DownloadBytes(mxc) - if err != nil { - portal.log.Errorfln("Failed to download media in %s: %v", eventID, err) - return nil - } - if file != nil { - data, err = file.Decrypt(data) - if err != nil { - portal.log.Errorfln("Failed to decrypt media in %s: %v", eventID, err) - return nil - } - } - - //url, mediaKey, fileEncSHA256, fileSHA256, fileLength, err := sender.Conn.Upload(bytes.NewReader(data), mediaType) - //if err != nil { - // portal.log.Errorfln("Failed to upload media in %s: %v", eventID, err) - // return nil - //} - // - //return &MediaUpload{ - // Caption: caption, - // URL: url, - // MediaKey: mediaKey, - // FileEncSHA256: fileEncSHA256, - // FileSHA256: fileSHA256, - // FileLength: fileLength, - // Thumbnail: portal.downloadThumbnail(content, eventID), - //} - return nil -} - type MediaUpload struct { Caption string URL string @@ -2098,145 +2052,6 @@ func (portal *Portal) convertMatrixMessageSkype(sender *User, evt *event.Event) return info, sender, content } -func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) (*waProto.WebMessageInfo, *User, *event.MessageEventContent) { - content, ok := evt.Content.Parsed.(*event.MessageEventContent) - if !ok { - portal.log.Debugfln("Failed to handle event %s: unexpected parsed content type %T", evt.ID, evt.Content.Parsed) - return nil, sender, content - } - - ts := uint64(evt.Timestamp / 1000) - status := waProto.WebMessageInfo_ERROR - fromMe := true - info := &waProto.WebMessageInfo{ - Key: &waProto.MessageKey{ - FromMe: &fromMe, - Id: makeMessageID(), - RemoteJid: &portal.Key.JID, - }, - MessageTimestamp: &ts, - Message: &waProto.Message{}, - Status: &status, - } - //ctxInfo := &waProto.ContextInfo{} - replyToID := content.GetReplyTo() - if len(replyToID) > 0 { - content.RemoveReplyFallback() - msg := portal.bridge.DB.Message.GetByMXID(replyToID) - //if msg != nil && msg.Content != nil { - if msg != nil { - //ctxInfo.StanzaId = &msg.JID - //ctxInfo.Participant = &msg.Sender - //ctxInfo.QuotedMessage = msg.Content - } - } - relaybotFormatted := false - if sender.NeedsRelaybot(portal) { - if !portal.HasRelaybot() { - if sender.HasSession() { - portal.log.Debugln("Database says", sender.MXID, "not in chat and no relaybot, but trying to send anyway") - } else { - portal.log.Debugln("Ignoring message from", sender.MXID, "in chat with no relaybot") - return nil, sender, content - } - } else { - relaybotFormatted = portal.addRelaybotFormat(sender, content) - sender = portal.bridge.Relaybot - } - } - if evt.Type == event.EventSticker { - content.MsgType = event.MsgImage - } -fmt.Println("convertMatrixMessage content.MsgType: ", content.MsgType) - switch content.MsgType { - case event.MsgText, event.MsgEmote, event.MsgNotice: - text := content.Body - if content.Format == event.FormatHTML { - text = portal.bridge.Formatter.ParseMatrix(content.FormattedBody) - } - if content.MsgType == event.MsgEmote && !relaybotFormatted { - text = "/me " + text - } - //ctxInfo.MentionedJid = mentionRegex.FindAllString(text, -1) - //for index, mention := range ctxInfo.MentionedJid { - // ctxInfo.MentionedJid[index] = mention[1:] + whatsappExt.NewUserSuffix - //} - //if ctxInfo.StanzaId != nil || ctxInfo.MentionedJid != nil { - // info.Message.ExtendedTextMessage = &waProto.ExtendedTextMessage{ - // Text: &text, - // ContextInfo: ctxInfo, - // } - //} else { - // info.Message.Conversation = &text - //} - case event.MsgImage: - media := portal.preprocessMatrixMedia(sender, relaybotFormatted, content, evt.ID, whatsapp.MediaImage) - if media == nil { - return nil, sender, content - } - info.Message.ImageMessage = &waProto.ImageMessage{ - Caption: &media.Caption, - JpegThumbnail: media.Thumbnail, - Url: &media.URL, - MediaKey: media.MediaKey, - Mimetype: &content.GetInfo().MimeType, - FileEncSha256: media.FileEncSHA256, - FileSha256: media.FileSHA256, - FileLength: &media.FileLength, - } - case event.MsgVideo: - media := portal.preprocessMatrixMedia(sender, relaybotFormatted, content, evt.ID, whatsapp.MediaVideo) - if media == nil { - return nil, sender, content - } - duration := uint32(content.GetInfo().Duration) - info.Message.VideoMessage = &waProto.VideoMessage{ - Caption: &media.Caption, - JpegThumbnail: media.Thumbnail, - Url: &media.URL, - MediaKey: media.MediaKey, - Mimetype: &content.GetInfo().MimeType, - Seconds: &duration, - FileEncSha256: media.FileEncSHA256, - FileSha256: media.FileSHA256, - FileLength: &media.FileLength, - } - case event.MsgAudio: - media := portal.preprocessMatrixMedia(sender, relaybotFormatted, content, evt.ID, whatsapp.MediaAudio) - if media == nil { - return nil, sender, content - } - duration := uint32(content.GetInfo().Duration) - info.Message.AudioMessage = &waProto.AudioMessage{ - Url: &media.URL, - MediaKey: media.MediaKey, - Mimetype: &content.GetInfo().MimeType, - Seconds: &duration, - FileEncSha256: media.FileEncSHA256, - FileSha256: media.FileSHA256, - FileLength: &media.FileLength, - } - case event.MsgFile: - media := portal.preprocessMatrixMedia(sender, relaybotFormatted, content, evt.ID, whatsapp.MediaDocument) - if media == nil { - return nil, sender, content - } - info.Message.DocumentMessage = &waProto.DocumentMessage{ - Url: &media.URL, - FileName: &content.Body, - MediaKey: media.MediaKey, - Mimetype: &content.GetInfo().MimeType, - FileEncSha256: media.FileEncSHA256, - FileSha256: media.FileSHA256, - FileLength: &media.FileLength, - } - default: - portal.log.Debugln("Unhandled Matrix event %s: unknown msgtype %s", evt.ID, content.MsgType) - return nil, sender, content - } - return info, sender, content -} - func (portal *Portal) wasMessageSent(sender *User, id string) bool { //_, err := sender.Conn.LoadMessagesAfter(portal.Key.JID, id, true, 0) //if err != nil { diff --git a/puppet.go b/puppet.go index 31543dd..15bdfdc 100644 --- a/puppet.go +++ b/puppet.go @@ -15,7 +15,7 @@ import ( "github.com/kelaresg/matrix-skype/database" "github.com/kelaresg/matrix-skype/types" - "github.com/kelaresg/matrix-skype/whatsapp-ext" + //"github.com/kelaresg/matrix-skype/whatsapp-ext" ) func (bridge *Bridge) ParsePuppetMXID(mxid id.UserID) (types.SkypeID, bool) { @@ -134,10 +134,8 @@ func (bridge *Bridge) NewPuppet(dbPuppet *database.Puppet) *Puppet { MXID: id.NewUserID( bridge.Config.Bridge.FormatUsername( - // dbPuppet.JID, - //), strings.Replace( - strings.Replace(dbPuppet.JID, whatsappExt.NewUserSuffix, "", 1), + strings.Replace(dbPuppet.JID, skypeExt.NewUserSuffix, "", 1), ":", "-", -1, @@ -164,7 +162,7 @@ type Puppet struct { } func (puppet *Puppet) PhoneNumber() string { - return strings.Replace(puppet.JID, whatsappExt.NewUserSuffix, "", 1) + return strings.Replace(puppet.JID, skypeExt.NewUserSuffix, "", 1) } func (puppet *Puppet) IntentFor(portal *Portal) *appservice.IntentAPI { @@ -272,7 +270,7 @@ func (puppet *Puppet) UpdateName(source *User, contact skype.Contact) bool { func (puppet *Puppet) updatePortalMeta(meta func(portal *Portal)) { if puppet.bridge.Config.Bridge.PrivateChatPortalMeta { - jid := strings.Replace(puppet.JID, whatsappExt.NewUserSuffix, "", 1) + jid := strings.Replace(puppet.JID, skypeExt.NewUserSuffix, "", 1) for _, portal := range puppet.bridge.GetAllPortalsByJID(jid) { meta(portal) } diff --git a/skype-ext/chat.go b/skype-ext/chat.go index 70453dd..28845e4 100644 --- a/skype-ext/chat.go +++ b/skype-ext/chat.go @@ -18,9 +18,8 @@ package skypeExt import ( "encoding/json" + skype "github.com/kelaresg/go-skypeapi" "strings" - - "github.com/Rhymen/go-whatsapp" ) type ChatUpdateCommand string @@ -155,7 +154,7 @@ func (cud *ChatUpdateData) UnmarshalJSON(data []byte) error { } type ChatUpdateHandler interface { - whatsapp.Handler + skype.Handler HandleChatUpdate(ChatUpdate) } diff --git a/skype-ext/cmd.go b/skype-ext/cmd.go index fcbda17..75ef250 100644 --- a/skype-ext/cmd.go +++ b/skype-ext/cmd.go @@ -18,9 +18,8 @@ package skypeExt import ( "encoding/json" + skype "github.com/kelaresg/go-skypeapi" "strings" - - "github.com/Rhymen/go-whatsapp" ) type CommandType string @@ -41,7 +40,7 @@ type Command struct { } type CommandHandler interface { - whatsapp.Handler + skype.Handler HandleCommand(Command) } diff --git a/user.go b/user.go index 89bed9d..216e94d 100644 --- a/user.go +++ b/user.go @@ -12,20 +12,20 @@ import ( "sync" "time" - "github.com/pkg/errors" + //"github.com/pkg/errors" "github.com/skip2/go-qrcode" log "maunium.net/go/maulogger/v2" "maunium.net/go/mautrix" - "github.com/Rhymen/go-whatsapp" - waProto "github.com/Rhymen/go-whatsapp/binary/proto" + //"github.com/Rhymen/go-whatsapp" + //waProto "github.com/Rhymen/go-whatsapp/binary/proto" "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" "github.com/kelaresg/matrix-skype/database" "github.com/kelaresg/matrix-skype/types" - "github.com/kelaresg/matrix-skype/whatsapp-ext" + //"github.com/kelaresg/matrix-skype/whatsapp-ext" ) type User struct { @@ -587,13 +587,13 @@ func (user *User) syncPortals(chatMap map[string]skype.Conversation, createAll b } } -func (user *User) HandleContactList(contacts []whatsapp.Contact) { - contactMap := make(map[string]whatsapp.Contact) - for _, contact := range contacts { - contactMap[contact.Jid] = contact - } - // go user.syncPuppets(contactMap) -} +//func (user *User) HandleContactList(contacts []whatsapp.Contact) { +// contactMap := make(map[string]whatsapp.Contact) +// for _, contact := range contacts { +// contactMap[contact.Jid] = contact +// } +// // go user.syncPuppets(contactMap) +//} func (user *User) syncPuppets(contacts map[string]skype.Contact) { if contacts == nil { @@ -636,20 +636,6 @@ func (user *User) updateLastConnectionIfNecessary() { } func (user *User) HandleError(err error) { - if errors.Cause(err) != whatsapp.ErrInvalidWsData { - user.log.Errorfln("WhatsApp error: %v", err) - } - if closed, ok := err.(*whatsapp.ErrConnectionClosed); ok { - if closed.Code == 1000 && user.cleanDisconnection { - user.cleanDisconnection = false - user.log.Infoln("Clean disconnection by server") - return - } - go user.tryReconnect(fmt.Sprintf("Your WhatsApp connection was closed with websocket status code %d", closed.Code)) - } else if failed, ok := err.(*whatsapp.ErrConnectionFailed); ok { - user.ConnectionErrors++ - go user.tryReconnect(fmt.Sprintf("Your WhatsApp connection failed: %v", failed.Err)) - } // Otherwise unknown error, probably mostly harmless } @@ -762,21 +748,21 @@ func (user *User) HandleImageMessage(message skype.Resource) { user.putMessage(PortalMessage{message.Jid, user, message, uint64(message.Timestamp)}) } -func (user *User) HandleStickerMessage(message whatsapp.StickerMessage) { - user.putMessage(PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp}) -} - -func (user *User) HandleVideoMessage(message whatsapp.VideoMessage) { - user.putMessage(PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp}) -} - -func (user *User) HandleAudioMessage(message whatsapp.AudioMessage) { - user.putMessage(PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp}) -} - -func (user *User) HandleDocumentMessage(message whatsapp.DocumentMessage) { - user.putMessage(PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp}) -} +//func (user *User) HandleStickerMessage(message whatsapp.StickerMessage) { +// user.putMessage(PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp}) +//} +// +//func (user *User) HandleVideoMessage(message whatsapp.VideoMessage) { +// user.putMessage(PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp}) +//} +// +//func (user *User) HandleAudioMessage(message whatsapp.AudioMessage) { +// user.putMessage(PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp}) +//} +// +//func (user *User) HandleDocumentMessage(message whatsapp.DocumentMessage) { +// user.putMessage(PortalMessage{message.Info.RemoteJid, user, message, message.Info.Timestamp}) +//} func (user *User) HandleContactMessage(message skype.Resource) { user.log.Debugf("HandleContactMessage: ", message) @@ -798,40 +784,40 @@ type FakeMessage struct { Alert bool } -func (user *User) HandleCallInfo(info whatsappExt.CallInfo) { - if info.Data != nil { - return - } - data := FakeMessage{ - ID: info.ID, - } - switch info.Type { - case whatsappExt.CallOffer: - if !user.bridge.Config.Bridge.CallNotices.Start { - return - } - data.Text = "Incoming call" - data.Alert = true - case whatsappExt.CallOfferVideo: - if !user.bridge.Config.Bridge.CallNotices.Start { - return - } - data.Text = "Incoming video call" - data.Alert = true - case whatsappExt.CallTerminate: - if !user.bridge.Config.Bridge.CallNotices.End { - return - } - data.Text = "Call ended" - data.ID += "E" - default: - return - } - portal := user.GetPortalByJID(info.From) - if portal != nil { - portal.messages <- PortalMessage{info.From, user, data, 0} - } -} +//func (user *User) HandleCallInfo(info whatsappExt.CallInfo) { +// if info.Data != nil { +// return +// } +// data := FakeMessage{ +// ID: info.ID, +// } +// switch info.Type { +// case whatsappExt.CallOffer: +// if !user.bridge.Config.Bridge.CallNotices.Start { +// return +// } +// data.Text = "Incoming call" +// data.Alert = true +// case whatsappExt.CallOfferVideo: +// if !user.bridge.Config.Bridge.CallNotices.Start { +// return +// } +// data.Text = "Incoming video call" +// data.Alert = true +// case whatsappExt.CallTerminate: +// if !user.bridge.Config.Bridge.CallNotices.End { +// return +// } +// data.Text = "Call ended" +// data.ID += "E" +// default: +// return +// } +// portal := user.GetPortalByJID(info.From) +// if portal != nil { +// portal.messages <- PortalMessage{info.From, user, data, 0} +// } +//} func (user *User) HandleTypingStatus(info skype.Resource) { sendId := info.SendId + skypeExt.NewUserSuffix @@ -904,62 +890,62 @@ func (user *User) HandlePresence(info skype.Resource) { } } -func (user *User) HandlePresenceWA(info whatsappExt.Presence) { - puppet := user.bridge.GetPuppetByJID(info.SenderJID) - switch info.Status { - case whatsapp.PresenceUnavailable: - _ = puppet.DefaultIntent().SetPresence("offline") - case whatsapp.PresenceAvailable: - if len(puppet.typingIn) > 0 && puppet.typingAt+15 > time.Now().Unix() { - portal := user.bridge.GetPortalByMXID(puppet.typingIn) - _, _ = puppet.IntentFor(portal).UserTyping(puppet.typingIn, false, 0) - puppet.typingIn = "" - puppet.typingAt = 0 - } - _ = puppet.DefaultIntent().SetPresence("online") - case whatsapp.PresenceComposing: - portal := user.GetPortalByJID(info.JID) - if len(puppet.typingIn) > 0 && puppet.typingAt+15 > time.Now().Unix() { - if puppet.typingIn == portal.MXID { - return - } - _, _ = puppet.IntentFor(portal).UserTyping(puppet.typingIn, false, 0) - } - puppet.typingIn = portal.MXID - puppet.typingAt = time.Now().Unix() - _, _ = puppet.IntentFor(portal).UserTyping(portal.MXID, true, 15*1000) - _ = puppet.DefaultIntent().SetPresence("online") - } -} +//func (user *User) HandlePresenceWA(info whatsappExt.Presence) { +// puppet := user.bridge.GetPuppetByJID(info.SenderJID) +// switch info.Status { +// case whatsapp.PresenceUnavailable: +// _ = puppet.DefaultIntent().SetPresence("offline") +// case whatsapp.PresenceAvailable: +// if len(puppet.typingIn) > 0 && puppet.typingAt+15 > time.Now().Unix() { +// portal := user.bridge.GetPortalByMXID(puppet.typingIn) +// _, _ = puppet.IntentFor(portal).UserTyping(puppet.typingIn, false, 0) +// puppet.typingIn = "" +// puppet.typingAt = 0 +// } +// _ = puppet.DefaultIntent().SetPresence("online") +// case whatsapp.PresenceComposing: +// portal := user.GetPortalByJID(info.JID) +// if len(puppet.typingIn) > 0 && puppet.typingAt+15 > time.Now().Unix() { +// if puppet.typingIn == portal.MXID { +// return +// } +// _, _ = puppet.IntentFor(portal).UserTyping(puppet.typingIn, false, 0) +// } +// puppet.typingIn = portal.MXID +// puppet.typingAt = time.Now().Unix() +// _, _ = puppet.IntentFor(portal).UserTyping(portal.MXID, true, 15*1000) +// _ = puppet.DefaultIntent().SetPresence("online") +// } +//} -func (user *User) HandleMsgInfo(info whatsappExt.MsgInfo) { - if (info.Command == whatsappExt.MsgInfoCommandAck || info.Command == whatsappExt.MsgInfoCommandAcks) && info.Acknowledgement == whatsappExt.AckMessageRead { - portal := user.GetPortalByJID(info.ToJID) - if len(portal.MXID) == 0 { - return - } - - go func() { - intent := user.bridge.GetPuppetByJID(info.SenderJID).IntentFor(portal) - for _, id := range info.IDs { - msg := user.bridge.DB.Message.GetByJID(portal.Key, id) - if msg == nil { - continue - } - - err := intent.MarkRead(portal.MXID, msg.MXID) - if err != nil { - user.log.Warnln("Failed to mark message %s as read by %s: %v", msg.MXID, info.SenderJID, err) - } - } - }() - } -} +//func (user *User) HandleMsgInfo(info whatsappExt.MsgInfo) { +// if (info.Command == whatsappExt.MsgInfoCommandAck || info.Command == whatsappExt.MsgInfoCommandAcks) && info.Acknowledgement == whatsappExt.AckMessageRead { +// portal := user.GetPortalByJID(info.ToJID) +// if len(portal.MXID) == 0 { +// return +// } +// +// go func() { +// intent := user.bridge.GetPuppetByJID(info.SenderJID).IntentFor(portal) +// for _, id := range info.IDs { +// msg := user.bridge.DB.Message.GetByJID(portal.Key, id) +// if msg == nil { +// continue +// } +// +// err := intent.MarkRead(portal.MXID, msg.MXID) +// if err != nil { +// user.log.Warnln("Failed to mark message %s as read by %s: %v", msg.MXID, info.SenderJID, err) +// } +// } +// }() +// } +//} func (user *User) HandleCommand(cmd skypeExt.Command) { switch cmd.Type { case skypeExt.CommandPicture: - if strings.HasSuffix(cmd.JID, whatsappExt.NewUserSuffix) { + if strings.HasSuffix(cmd.JID, skypeExt.NewUserSuffix) { puppet := user.bridge.GetPuppetByJID(cmd.JID) go puppet.UpdateAvatar(user, cmd.ProfilePicInfo) } else { @@ -1145,9 +1131,9 @@ func (user *User) HandleJsonMessage(message string) { user.updateLastConnectionIfNecessary() } -func (user *User) HandleRawMessage(message *waProto.WebMessageInfo) { - user.updateLastConnectionIfNecessary() -} +//func (user *User) HandleRawMessage(message *waProto.WebMessageInfo) { +// user.updateLastConnectionIfNecessary() +//} func (user *User) NeedsRelaybot(portal *Portal) bool { return false diff --git a/whatsapp-ext/call.go b/whatsapp-ext/call.go deleted file mode 100644 index 29575c3..0000000 --- a/whatsapp-ext/call.go +++ /dev/null @@ -1,72 +0,0 @@ -// matrix-skype - A Matrix-WhatsApp puppeting bridge. -// Copyright (C) 2019 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 whatsappExt - -import ( - "encoding/json" - "strings" - - "github.com/Rhymen/go-whatsapp" -) - -type CallInfoType string - -const ( - CallOffer CallInfoType = "offer" - CallOfferVideo CallInfoType = "offer_video" - CallTransport CallInfoType = "transport" - CallRelayLatency CallInfoType = "relaylatency" - CallTerminate CallInfoType = "terminate" -) - -type CallInfo struct { - ID string `json:"id"` - Type CallInfoType `json:"type"` - From string `json:"from"` - - Platform string `json:"platform"` - Version []int `json:"version"` - - Data [][]interface{} `json:"data"` -} - -type CallInfoHandler interface { - whatsapp.Handler - HandleCallInfo(CallInfo) -} - -func (ext *ExtendedConn) handleMessageCall(message []byte) { - var event CallInfo - err := json.Unmarshal(message, &event) - if err != nil { - ext.jsonParseError(err) - return - } - event.From = strings.Replace(event.From, OldUserSuffix, NewUserSuffix, 1) - for _, handler := range ext.handlers { - callInfoHandler, ok := handler.(CallInfoHandler) - if !ok { - continue - } - - if ext.shouldCallSynchronously(callInfoHandler) { - callInfoHandler.HandleCallInfo(event) - } else { - go callInfoHandler.HandleCallInfo(event) - } - } -} diff --git a/whatsapp-ext/chat.go b/whatsapp-ext/chat.go deleted file mode 100644 index 8de0a99..0000000 --- a/whatsapp-ext/chat.go +++ /dev/null @@ -1,174 +0,0 @@ -// matrix-skype - A Matrix-WhatsApp puppeting bridge. -// Copyright (C) 2019 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 whatsappExt - -import ( - "encoding/json" - "strings" - - "github.com/Rhymen/go-whatsapp" -) - -type ChatUpdateCommand string - -const ( - ChatUpdateCommandAction ChatUpdateCommand = "action" -) - -type ChatUpdate struct { - JID string `json:"id"` - Command ChatUpdateCommand `json:"cmd"` - Data ChatUpdateData `json:"data"` -} - -type ChatActionType string - -const ( - ChatActionNameChange ChatActionType = "subject" - ChatActionAddTopic ChatActionType = "desc_add" - ChatActionRemoveTopic ChatActionType = "desc_remove" - ChatActionRestrict ChatActionType = "restrict" - ChatActionAnnounce ChatActionType = "announce" - ChatActionPromote ChatActionType = "promote" - ChatActionDemote ChatActionType = "demote" - ChatActionRemove ChatActionType = "remove" - ChatActionAdd ChatActionType = "add" - ChatActionIntroduce ChatActionType = "introduce" - ChatActionCreate ChatActionType = "create" -) - -type ChatUpdateData struct { - Action ChatActionType - SenderJID string - - NameChange struct { - Name string `json:"subject"` - SetAt int64 `json:"s_t"` - SetBy string `json:"s_o"` - } - - AddTopic struct { - Topic string `json:"desc"` - ID string `json:"descId"` - SetAt int64 `json:"descTime"` - } - - RemoveTopic struct { - ID string `json:"descId"` - } - - Restrict bool - - Announce bool - - PermissionChange struct { - JIDs []string `json:"participants"` - } - - MemberAction struct { - JIDs []string `json:"participants"` - } - - Create struct { - Creation int64 `json:"creation"` - Name string `json:"subject"` - SetAt int64 `json:"s_t"` - SetBy string `json:"s_o"` - Admins []string `json:"admins"` - SuperAdmins []string `json:"superadmins"` - Regulars []string `json:"regulars"` - } -} - -func (cud *ChatUpdateData) UnmarshalJSON(data []byte) error { - var arr []json.RawMessage - err := json.Unmarshal(data, &arr) - if err != nil { - return err - } else if len(arr) < 3 { - return nil - } - - err = json.Unmarshal(arr[0], &cud.Action) - if err != nil { - return err - } - - err = json.Unmarshal(arr[1], &cud.SenderJID) - if err != nil { - return err - } - cud.SenderJID = strings.Replace(cud.SenderJID, OldUserSuffix, NewUserSuffix, 1) - - var unmarshalTo interface{} - switch cud.Action { - case ChatActionNameChange: - unmarshalTo = &cud.NameChange - case ChatActionAddTopic: - unmarshalTo = &cud.AddTopic - case ChatActionRemoveTopic: - unmarshalTo = &cud.RemoveTopic - case ChatActionRestrict: - unmarshalTo = &cud.Restrict - case ChatActionAnnounce: - unmarshalTo = &cud.Announce - case ChatActionPromote, ChatActionDemote: - unmarshalTo = &cud.PermissionChange - case ChatActionAdd, ChatActionRemove: - unmarshalTo = &cud.MemberAction - case ChatActionCreate: - unmarshalTo = &cud.Create - default: - return nil - } - err = json.Unmarshal(arr[2], unmarshalTo) - if err != nil { - return err - } - cud.NameChange.SetBy = strings.Replace(cud.NameChange.SetBy, OldUserSuffix, NewUserSuffix, 1) - for index, jid := range cud.PermissionChange.JIDs { - cud.PermissionChange.JIDs[index] = strings.Replace(jid, OldUserSuffix, NewUserSuffix, 1) - } - return nil -} - -type ChatUpdateHandler interface { - whatsapp.Handler - HandleChatUpdate(ChatUpdate) -} - -func (ext *ExtendedConn) handleMessageChatUpdate(message []byte) { - var event ChatUpdate - err := json.Unmarshal(message, &event) - if err != nil { - ext.jsonParseError(err) - return - } - event.JID = strings.Replace(event.JID, OldUserSuffix, NewUserSuffix, 1) - for _, handler := range ext.handlers { - chatUpdateHandler, ok := handler.(ChatUpdateHandler) - if !ok { - continue - } - - if ext.shouldCallSynchronously(chatUpdateHandler) { - chatUpdateHandler.HandleChatUpdate(event) - } else { - go chatUpdateHandler.HandleChatUpdate(event) - } - } -} diff --git a/whatsapp-ext/cmd.go b/whatsapp-ext/cmd.go deleted file mode 100644 index 0954df3..0000000 --- a/whatsapp-ext/cmd.go +++ /dev/null @@ -1,69 +0,0 @@ -// matrix-skype - A Matrix-WhatsApp puppeting bridge. -// Copyright (C) 2019 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 whatsappExt - -import ( - "encoding/json" - "strings" - - "github.com/Rhymen/go-whatsapp" -) - -type CommandType string - -const ( - CommandPicture CommandType = "picture" - CommandDisconnect CommandType = "disconnect" -) - -type Command struct { - Type CommandType `json:"type"` - JID string `json:"jid"` - - *ProfilePicInfo - Kind string `json:"kind"` - - Raw json.RawMessage `json:"-"` -} - -type CommandHandler interface { - whatsapp.Handler - HandleCommand(Command) -} - -func (ext *ExtendedConn) handleMessageCommand(message []byte) { - var event Command - err := json.Unmarshal(message, &event) - if err != nil { - ext.jsonParseError(err) - return - } - event.Raw = message - event.JID = strings.Replace(event.JID, OldUserSuffix, NewUserSuffix, 1) - for _, handler := range ext.handlers { - commandHandler, ok := handler.(CommandHandler) - if !ok { - continue - } - - if ext.shouldCallSynchronously(commandHandler) { - commandHandler.HandleCommand(event) - } else { - go commandHandler.HandleCommand(event) - } - } -} diff --git a/whatsapp-ext/conn.go b/whatsapp-ext/conn.go deleted file mode 100644 index 8ce4345..0000000 --- a/whatsapp-ext/conn.go +++ /dev/null @@ -1,65 +0,0 @@ -// matrix-skype - A Matrix-WhatsApp puppeting bridge. -// Copyright (C) 2019 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 whatsappExt - -import ( - "encoding/json" - - "github.com/Rhymen/go-whatsapp" -) - -type ConnInfo struct { - ProtocolVersion []int `json:"protoVersion"` - BinaryVersion int `json:"binVersion"` - Phone struct { - WhatsAppVersion string `json:"wa_version"` - MCC string `json:"mcc"` - MNC string `json:"mnc"` - OSVersion string `json:"os_version"` - DeviceManufacturer string `json:"device_manufacturer"` - DeviceModel string `json:"device_model"` - OSBuildNumber string `json:"os_build_number"` - } `json:"phone"` - Features map[string]interface{} `json:"features"` - PushName string `json:"pushname"` -} - -type ConnInfoHandler interface { - whatsapp.Handler - HandleConnInfo(ConnInfo) -} - -func (ext *ExtendedConn) handleMessageConn(message []byte) { - var event ConnInfo - err := json.Unmarshal(message, &event) - if err != nil { - ext.jsonParseError(err) - return - } - for _, handler := range ext.handlers { - connInfoHandler, ok := handler.(ConnInfoHandler) - if !ok { - continue - } - - if ext.shouldCallSynchronously(connInfoHandler) { - connInfoHandler.HandleConnInfo(event) - } else { - go connInfoHandler.HandleConnInfo(event) - } - } -} diff --git a/whatsapp-ext/jsonmessage.go b/whatsapp-ext/jsonmessage.go deleted file mode 100644 index e0ac474..0000000 --- a/whatsapp-ext/jsonmessage.go +++ /dev/null @@ -1,105 +0,0 @@ -// matrix-skype - A Matrix-WhatsApp puppeting bridge. -// Copyright (C) 2019 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 whatsappExt - -import ( - "encoding/json" - - "github.com/Rhymen/go-whatsapp" -) - -type JSONMessage []json.RawMessage - -type JSONMessageType string - -const ( - MessageMsgInfo JSONMessageType = "MsgInfo" - MessageMsg JSONMessageType = "Msg" - MessagePresence JSONMessageType = "Presence" - MessageStream JSONMessageType = "Stream" - MessageConn JSONMessageType = "Conn" - MessageProps JSONMessageType = "Props" - MessageCmd JSONMessageType = "Cmd" - MessageChat JSONMessageType = "Chat" - MessageCall JSONMessageType = "Call" -) - -func (ext *ExtendedConn) HandleError(error) {} - -type UnhandledJSONMessageHandler interface { - whatsapp.Handler - HandleUnhandledJSONMessage(string) -} - -type JSONParseErrorHandler interface { - whatsapp.Handler - HandleJSONParseError(error) -} - -func (ext *ExtendedConn) jsonParseError(err error) { - for _, handler := range ext.handlers { - errorHandler, ok := handler.(JSONParseErrorHandler) - if !ok { - continue - } - errorHandler.HandleJSONParseError(err) - } -} - -func (ext *ExtendedConn) HandleJsonMessage(message string) { - msg := JSONMessage{} - err := json.Unmarshal([]byte(message), &msg) - if err != nil || len(msg) < 2 { - ext.jsonParseError(err) - return - } - - var msgType JSONMessageType - json.Unmarshal(msg[0], &msgType) - - switch msgType { - case MessagePresence: - ext.handleMessagePresence(msg[1]) - case MessageStream: - ext.handleMessageStream(msg[1:]) - case MessageConn: - ext.handleMessageConn(msg[1]) - case MessageProps: - ext.handleMessageProps(msg[1]) - case MessageMsgInfo, MessageMsg: - ext.handleMessageMsgInfo(msgType, msg[1]) - case MessageCmd: - ext.handleMessageCommand(msg[1]) - case MessageChat: - ext.handleMessageChatUpdate(msg[1]) - case MessageCall: - ext.handleMessageCall(msg[1]) - default: - for _, handler := range ext.handlers { - ujmHandler, ok := handler.(UnhandledJSONMessageHandler) - if !ok { - continue - } - - if ext.shouldCallSynchronously(ujmHandler) { - ujmHandler.HandleUnhandledJSONMessage(message) - } else { - go ujmHandler.HandleUnhandledJSONMessage(message) - } - } - } -} diff --git a/whatsapp-ext/msginfo.go b/whatsapp-ext/msginfo.go deleted file mode 100644 index 702c322..0000000 --- a/whatsapp-ext/msginfo.go +++ /dev/null @@ -1,95 +0,0 @@ -// matrix-skype - A Matrix-WhatsApp puppeting bridge. -// Copyright (C) 2019 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 whatsappExt - -import ( - "encoding/json" - "strings" - - "github.com/Rhymen/go-whatsapp" -) - -type MsgInfoCommand string - -const ( - MsgInfoCommandAck MsgInfoCommand = "ack" - MsgInfoCommandAcks MsgInfoCommand = "acks" -) - -type Acknowledgement int - -const ( - AckMessageSent Acknowledgement = 1 - AckMessageDelivered Acknowledgement = 2 - AckMessageRead Acknowledgement = 3 -) - -type JSONStringOrArray []string - -func (jsoa *JSONStringOrArray) UnmarshalJSON(data []byte) error { - var str string - if json.Unmarshal(data, &str) == nil { - *jsoa = []string{str} - return nil - } - var strs []string - json.Unmarshal(data, &strs) - *jsoa = strs - return nil -} - -type MsgInfo struct { - Command MsgInfoCommand `json:"cmd"` - IDs JSONStringOrArray `json:"id"` - Acknowledgement Acknowledgement `json:"ack"` - MessageFromJID string `json:"from"` - SenderJID string `json:"participant"` - ToJID string `json:"to"` - Timestamp int64 `json:"t"` -} - -type MsgInfoHandler interface { - whatsapp.Handler - HandleMsgInfo(MsgInfo) -} - -func (ext *ExtendedConn) handleMessageMsgInfo(msgType JSONMessageType, message []byte) { - var event MsgInfo - err := json.Unmarshal(message, &event) - if err != nil { - ext.jsonParseError(err) - return - } - event.MessageFromJID = strings.Replace(event.MessageFromJID, OldUserSuffix, NewUserSuffix, 1) - event.SenderJID = strings.Replace(event.SenderJID, OldUserSuffix, NewUserSuffix, 1) - event.ToJID = strings.Replace(event.ToJID, OldUserSuffix, NewUserSuffix, 1) - if msgType == MessageMsg { - event.SenderJID = event.ToJID - } - for _, handler := range ext.handlers { - msgInfoHandler, ok := handler.(MsgInfoHandler) - if !ok { - continue - } - - if ext.shouldCallSynchronously(msgInfoHandler) { - msgInfoHandler.HandleMsgInfo(event) - } else { - go msgInfoHandler.HandleMsgInfo(event) - } - } -} diff --git a/whatsapp-ext/presence.go b/whatsapp-ext/presence.go deleted file mode 100644 index 01365d2..0000000 --- a/whatsapp-ext/presence.go +++ /dev/null @@ -1,67 +0,0 @@ -// matrix-skype - A Matrix-WhatsApp puppeting bridge. -// Copyright (C) 2019 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 whatsappExt - -import ( - "encoding/json" - "strings" - - "github.com/Rhymen/go-whatsapp" -) - -type Presence struct { - JID string `json:"id"` - SenderJID string `json:"participant"` - Status whatsapp.Presence `json:"type"` - Timestamp int64 `json:"t"` - Deny bool `json:"deny"` -} - -type PresenceHandler interface { - whatsapp.Handler - HandlePresence(Presence) -} - -func (ext *ExtendedConn) handleMessagePresence(message []byte) { - var event Presence - err := json.Unmarshal(message, &event) - if err != nil { - ext.jsonParseError(err) - return - } - event.JID = strings.Replace(event.JID, OldUserSuffix, NewUserSuffix, 1) - if len(event.SenderJID) == 0 { - if strings.Index(event.JID,"@g.us") > -1 { - return - } - event.SenderJID = event.JID - } else { - event.SenderJID = strings.Replace(event.SenderJID, OldUserSuffix, NewUserSuffix, 1) - } - for _, handler := range ext.handlers { - presenceHandler, ok := handler.(PresenceHandler) - if !ok { - continue - } - - if ext.shouldCallSynchronously(presenceHandler) { - presenceHandler.HandlePresence(event) - } else { - go presenceHandler.HandlePresence(event) - } - } -} diff --git a/whatsapp-ext/props.go b/whatsapp-ext/props.go deleted file mode 100644 index 4245683..0000000 --- a/whatsapp-ext/props.go +++ /dev/null @@ -1,73 +0,0 @@ -// matrix-skype - A Matrix-WhatsApp puppeting bridge. -// Copyright (C) 2019 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 whatsappExt - -import ( - "encoding/json" - - "github.com/Rhymen/go-whatsapp" -) - -type ProtocolProps struct { - WebPresence bool `json:"webPresence"` - NotificationQuery bool `json:"notificationQuery"` - FacebookCrashLog bool `json:"fbCrashlog"` - Bucket string `json:"bucket"` - GIFSearch string `json:"gifSearch"` - Spam bool `json:"SPAM"` - SetBlock bool `json:"SET_BLOCK"` - MessageInfo bool `json:"MESSAGE_INFO"` - MaxFileSize int `json:"maxFileSize"` - Media int `json:"media"` - GroupNameLength int `json:"maxSubject"` - GroupDescriptionLength int `json:"groupDescLength"` - MaxParticipants int `json:"maxParticipants"` - VideoMaxEdge int `json:"videoMaxEdge"` - ImageMaxEdge int `json:"imageMaxEdge"` - ImageMaxKilobytes int `json:"imageMaxKBytes"` - Edit int `json:"edit"` - FwdUIStartTimestamp int `json:"fwdUiStartTs"` - GroupsV3 int `json:"groupsV3"` - RestrictGroups int `json:"restrictGroups"` - AnnounceGroups int `json:"announceGroups"` -} - -type ProtocolPropsHandler interface { - whatsapp.Handler - HandleProtocolProps(ProtocolProps) -} - -func (ext *ExtendedConn) handleMessageProps(message []byte) { - var event ProtocolProps - err := json.Unmarshal(message, &event) - if err != nil { - ext.jsonParseError(err) - return - } - for _, handler := range ext.handlers { - protocolPropsHandler, ok := handler.(ProtocolPropsHandler) - if !ok { - continue - } - - if ext.shouldCallSynchronously(protocolPropsHandler) { - protocolPropsHandler.HandleProtocolProps(event) - } else { - go protocolPropsHandler.HandleProtocolProps(event) - } - } -} diff --git a/whatsapp-ext/protomessage.go b/whatsapp-ext/protomessage.go deleted file mode 100644 index ca00f05..0000000 --- a/whatsapp-ext/protomessage.go +++ /dev/null @@ -1,59 +0,0 @@ -// matrix-skype - A Matrix-WhatsApp puppeting bridge. -// Copyright (C) 2019 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 whatsappExt - -import ( - "github.com/Rhymen/go-whatsapp" - "github.com/Rhymen/go-whatsapp/binary/proto" -) - -type MessageRevokeHandler interface { - whatsapp.Handler - HandleMessageRevoke(key MessageRevocation) -} - -type MessageRevocation struct { - Id string - RemoteJid string - FromMe bool - Participant string -} - -func (ext *ExtendedConn) HandleRawMessage(message *proto.WebMessageInfo) { - protoMsg := message.GetMessage().GetProtocolMessage() - if protoMsg != nil && protoMsg.GetType() == proto.ProtocolMessage_REVOKE { - key := protoMsg.GetKey() - deletedMessage := MessageRevocation{ - Id: key.GetId(), - RemoteJid: key.GetRemoteJid(), - FromMe: key.GetFromMe(), - Participant: key.GetParticipant(), - } - for _, handler := range ext.handlers { - mrHandler, ok := handler.(MessageRevokeHandler) - if !ok { - continue - } - - if ext.shouldCallSynchronously(mrHandler) { - mrHandler.HandleMessageRevoke(deletedMessage) - } else { - go mrHandler.HandleMessageRevoke(deletedMessage) - } - } - } -} diff --git a/whatsapp-ext/stream.go b/whatsapp-ext/stream.go deleted file mode 100644 index bd82672..0000000 --- a/whatsapp-ext/stream.go +++ /dev/null @@ -1,68 +0,0 @@ -// matrix-skype - A Matrix-WhatsApp puppeting bridge. -// Copyright (C) 2019 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 whatsappExt - -import ( - "encoding/json" - - "github.com/Rhymen/go-whatsapp" -) - -type StreamType string - -const ( - StreamUpdate = "update" - StreamSleep = "asleep" -) - -type StreamEvent struct { - Type StreamType - Boolean bool - Version string -} - -type StreamEventHandler interface { - whatsapp.Handler - HandleStreamEvent(StreamEvent) -} - -func (ext *ExtendedConn) handleMessageStream(message []json.RawMessage) { - var event StreamEvent - err := json.Unmarshal(message[0], &event.Type) - if err != nil { - ext.jsonParseError(err) - return - } - - if event.Type == StreamUpdate && len(message) > 4 { - json.Unmarshal(message[1], event.Boolean) - json.Unmarshal(message[2], event.Version) - } - - for _, handler := range ext.handlers { - streamHandler, ok := handler.(StreamEventHandler) - if !ok { - continue - } - - if ext.shouldCallSynchronously(streamHandler) { - streamHandler.HandleStreamEvent(event) - } else { - go streamHandler.HandleStreamEvent(event) - } - } -} diff --git a/whatsapp-ext/whatsapp.go b/whatsapp-ext/whatsapp.go deleted file mode 100644 index 5c356c3..0000000 --- a/whatsapp-ext/whatsapp.go +++ /dev/null @@ -1,206 +0,0 @@ -// matrix-skype - A Matrix-WhatsApp puppeting bridge. -// Copyright (C) 2019 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 whatsappExt - -import ( - "encoding/json" - "fmt" - "io" - "io/ioutil" - "net/http" - "strings" - - "github.com/Rhymen/go-whatsapp" -) - -const ( - OldUserSuffix = "@c.us" - //NewUserSuffix = "@s.whatsapp.net" - NewUserSuffix = "@s.skype.net" -) - -type ExtendedConn struct { - *whatsapp.Conn - - handlers []whatsapp.Handler -} - -func ExtendConn(conn *whatsapp.Conn) *ExtendedConn { - ext := &ExtendedConn{ - Conn: conn, - } - ext.Conn.AddHandler(ext) - return ext -} - -func (ext *ExtendedConn) AddHandler(handler whatsapp.Handler) { - ext.Conn.AddHandler(handler) - ext.handlers = append(ext.handlers, handler) -} - - -func (ext *ExtendedConn) RemoveHandler(handler whatsapp.Handler) bool { - ext.Conn.RemoveHandler(handler) - for i, v := range ext.handlers { - if v == handler { - ext.handlers = append(ext.handlers[:i], ext.handlers[i+1:]...) - return true - } - } - return false -} - -func (ext *ExtendedConn) RemoveHandlers() { - ext.Conn.RemoveHandlers() - ext.handlers = make([]whatsapp.Handler, 0) -} - -func (ext *ExtendedConn) shouldCallSynchronously(handler whatsapp.Handler) bool { - sh, ok := handler.(whatsapp.SyncHandler) - return ok && sh.ShouldCallSynchronously() -} - -func (ext *ExtendedConn) ShouldCallSynchronously() bool { - return true -} - -type GroupInfo struct { - JID string `json:"jid"` - OwnerJID string `json:"owner"` - - Name string `json:"subject"` - NameSetTime int64 `json:"subjectTime"` - NameSetBy string `json:"subjectOwner"` - - Topic string `json:"desc"` - TopicID string `json:"descId"` - TopicSetAt int64 `json:"descTime"` - TopicSetBy string `json:"descOwner"` - - GroupCreated int64 `json:"creation"` - - Status int16 `json:"status"` - - Participants []struct { - JID string `json:"id"` - IsAdmin bool `json:"isAdmin"` - IsSuperAdmin bool `json:"isSuperAdmin"` - } `json:"participants"` -} - -func (ext *ExtendedConn) GetGroupMetaData(jid string) (*GroupInfo, error) { - data, err := ext.Conn.GetGroupMetaData(jid) - if err != nil { - return nil, fmt.Errorf("failed to get group metadata: %v", err) - } - content := <-data - - info := &GroupInfo{} - err = json.Unmarshal([]byte(content), info) - if err != nil { - return info, fmt.Errorf("failed to unmarshal group metadata: %v", err) - } - - for index, participant := range info.Participants { - info.Participants[index].JID = strings.Replace(participant.JID, OldUserSuffix, NewUserSuffix, 1) - } - info.NameSetBy = strings.Replace(info.NameSetBy, OldUserSuffix, NewUserSuffix, 1) - info.TopicSetBy = strings.Replace(info.TopicSetBy, OldUserSuffix, NewUserSuffix, 1) - - return info, nil -} - -type ProfilePicInfo struct { - URL string `json:"eurl"` - Tag string `json:"tag"` - - Status int16 `json:"status"` -} - -func (ppi *ProfilePicInfo) Download() (io.ReadCloser, error) { - resp, err := http.Get(ppi.URL) - if err != nil { - return nil, err - } - return resp.Body, nil -} - -func (ppi *ProfilePicInfo) DownloadBytes() ([]byte, error) { - body, err := ppi.Download() - if err != nil { - return nil, err - } - defer body.Close() - data, err := ioutil.ReadAll(body) - return data, err -} - -func (ext *ExtendedConn) GetProfilePicThumb(jid string) (*ProfilePicInfo, error) { - data, err := ext.Conn.GetProfilePicThumb(jid) - if err != nil { - return nil, fmt.Errorf("failed to get avatar: %v", err) - } - content := <-data - info := &ProfilePicInfo{} - err = json.Unmarshal([]byte(content), info) - if err != nil { - return info, fmt.Errorf("failed to unmarshal avatar info: %v", err) - } - return info, nil -} - -func (ext *ExtendedConn) HandleGroupInvite(groupJid string, numbers[]string) (err error) { - var parts []string - parts = append(parts, numbers...) - _, err = ext.Conn.AddMember(groupJid, parts) - if err != nil { - fmt.Printf("%s Handle Invite err", err) - } - return -} - -func (ext *ExtendedConn) HandleGroupJoin(code string) (jid string, err error) { - return ext.Conn.GroupAcceptInviteCode(code) -} - -func (ext *ExtendedConn) HandleGroupKick(groupJid string, numbers[]string) (err error) { - var parts []string - parts = append(parts, numbers...) - _, err = ext.Conn.RemoveMember(groupJid, parts) - if err != nil { - fmt.Printf("%s Handle kick err", err) - } - return -} - -func (ext *ExtendedConn) HandleGroupCreate(subject string, numbers[]string) (err error) { - var parts []string - parts = append(parts, numbers...) - _, err = ext.Conn.CreateGroup(subject, parts) - if err != nil { - fmt.Printf("%s HandleGroupCreate err", err) - } - return -} - -func (ext *ExtendedConn) HandleGroupLeave(groupJid string) (err error) { - _, err = ext.Conn.LeaveGroup(groupJid) - if err != nil { - fmt.Printf("%s HandleGroupLeave err", err) - } - return -} From c4ed4894067f38aa87a946c69eadfcea725ff883 Mon Sep 17 00:00:00 2001 From: zhaoYangguang <1163765691@qq.com> Date: Thu, 3 Dec 2020 22:25:14 +0800 Subject: [PATCH 03/11] update command "create" --- commands.go | 113 +++++++++++++++++++++++++++++++++++++++------------- matrix.go | 2 +- 2 files changed, 86 insertions(+), 29 deletions(-) diff --git a/commands.go b/commands.go index 2df83ca..819dcf4 100644 --- a/commands.go +++ b/commands.go @@ -1,6 +1,7 @@ package main import ( + "errors" "fmt" skype "github.com/kelaresg/go-skypeapi" "github.com/kelaresg/matrix-skype/database" @@ -38,6 +39,7 @@ func NewCommandHandler(bridge *Bridge) *CommandHandler { type CommandEvent struct { Bot *appservice.IntentAPI Bridge *Bridge + Portal *Portal Handler *CommandHandler RoomID id.RoomID User *User @@ -142,7 +144,7 @@ func (handler *CommandHandler) CommandMux(ce *CommandEvent) { handler.CommandCreate(ce) } default: - ce.Reply("Unknown Command") + handler.CommandSpecialMux(ce) } } @@ -1151,50 +1153,105 @@ func (handler *CommandHandler) CommandJoin(ce *CommandEvent) { // } //} -const cmdCreateHelp = `create <_topic_> <_member user id_>,... - Create a group.` +const cmdCreateHelp = `create - Create a group chat.` func (handler *CommandHandler) CommandCreate(ce *CommandEvent) { - if len(ce.Args) < 2 { - ce.Reply("**Usage:** `create ,...`") + if ce.Portal != nil { + ce.Reply("This is already a portal room") return } - user := ce.User - topic := ce.Args[0] - members := skype.Members{} + members, err := ce.Bot.JoinedMembers(ce.RoomID) + if err != nil { + ce.Reply("Failed to get room members: %v", err) + return + } - // The user who created the group must be in the members and have "Admin" rights - userId := ce.User.Conn.UserProfile.Username + var roomNameEvent event.RoomNameEventContent + err = ce.Bot.StateEvent(ce.RoomID, event.StateRoomName, "", &roomNameEvent) + if err != nil && !errors.Is(err, mautrix.MNotFound) { + ce.Reply("Failed to get room name") + return + } else if len(roomNameEvent.Name) == 0 { + ce.Reply("Please set a name for the room first") + return + } + + var encryptionEvent event.EncryptionEventContent + err = ce.Bot.StateEvent(ce.RoomID, event.StateEncryption, "", &encryptionEvent) + if err != nil && !errors.Is(err, mautrix.MNotFound) { + ce.Reply("Failed to get room encryption status") + return + } + + var participants []string + for userID := range members.Joined { + jid, ok := handler.bridge.ParsePuppetMXID(userID) + if ok && jid != ce.User.JID { + participants = append(participants, jid) + } + } + + selfMembers := skype.Members{} member2 := skype.Member{ - Id: "8:" + userId, + Id: strings.Replace(ce.User.JID, skypeExt.NewUserSuffix,"", 1), Role: "Admin", } - members.Members = append(members.Members, member2) - members.Properties = skype.Properties{ + selfMembers.Members = append(selfMembers.Members, member2) + selfMembers.Properties = skype.Properties{ HistoryDisclosed: "true", - Topic: topic, + Topic: roomNameEvent.Name, + } + handler.log.Debugln("Create Group", roomNameEvent.Name, "with", selfMembers) + err = ce.User.Conn.HandleGroupCreate(selfMembers) + if err != nil { + ce.Reply("Failed to create group: %v", err) + return } - handler.log.Debugln("Create Group", topic, "with", members) - err := user.Conn.HandleGroupCreate(members) - inputArr := strings.Split(ce.Args[1], ",") - members = skype.Members{} - for _, memberId := range inputArr { - members.Members = append(members.Members, skype.Member{ + participantMembers := skype.Members{} + for _, participant := range participants { + participantArr := strings.Split(participant, "@") + memberId := id.Dec(participantArr[0]) + cond1 := "8-live-" + cond2 := "8-" + if strings.HasPrefix(memberId, cond1) { + memberId = strings.Replace(memberId, cond1, "8:live:", 1) + } else if strings.HasPrefix(memberId, cond2){ + memberId = strings.Replace(memberId, cond2, "8:", 1) + } + participantMembers.Members = append(participantMembers.Members, skype.Member{ Id: memberId, Role: "Admin", }) } - conversationId, ok := <-user.Conn.CreateChan + conversationId, ok := <-ce.User.Conn.CreateChan if ok { - err = user.Conn.AddMember(members, conversationId) - } - if err != nil { - ce.Reply("Please confirm that parameters is correct.") - } else { - ce.Reply("Syncing group list...") - time.Sleep(time.Duration(3) * time.Second) - ce.Reply("Syncing group list completed") + portal := handler.bridge.GetPortalByJID(database.GroupPortalKey(conversationId)) + portal.roomCreateLock.Lock() + defer portal.roomCreateLock.Unlock() + if len(portal.MXID) != 0 { + portal.log.Warnln("Detected race condition in room creation") + // TODO race condition, clean up the old room + } + portal.MXID = ce.RoomID + portal.Name = roomNameEvent.Name + portal.Encrypted = encryptionEvent.Algorithm == id.AlgorithmMegolmV1 + if !portal.Encrypted && handler.bridge.Config.Bridge.Encryption.Default { + _, err = portal.MainIntent().SendStateEvent(portal.MXID, event.StateEncryption, "", &event.EncryptionEventContent{Algorithm: id.AlgorithmMegolmV1}) + if err != nil { + portal.log.Warnln("Failed to enable e2be:", err) + } + portal.Encrypted = true + } + + portal.Update() + portal.UpdateBridgeInfo() + + err = ce.User.Conn.AddMember(participantMembers, conversationId) + ce.Reply("Successfully created Skype group %s", portal.Key.JID) } + + //ce.User.addPortalToCommunity(portal) } diff --git a/matrix.go b/matrix.go index 2c13705..4b66c4f 100644 --- a/matrix.go +++ b/matrix.go @@ -226,7 +226,7 @@ func (mx *MatrixHandler) HandlePuppetInvite(evt *event.Event, inviter *User, pup _, _ = intent.SendNotice(evt.RoomID, "Please invite the bridge bot first if you want to bridge to a WhatsApp group.") _, _ = intent.LeaveRoom(evt.RoomID) } else { - _, _ = intent.SendNotice(evt.RoomID, "This puppet will remain inactive until this room is bridged to a WhatsApp group.") + _, _ = intent.SendNotice(evt.RoomID, "This puppet will remain inactive until this room is bridged to a Skype group.") } } From 6bd6b9208ecd0a7c86a52f1b1c7128810d6ccef9 Mon Sep 17 00:00:00 2001 From: zhaoYangguang <1163765691@qq.com> Date: Thu, 3 Dec 2020 22:25:51 +0800 Subject: [PATCH 04/11] add special commands --- commands-special.go | 96 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 commands-special.go diff --git a/commands-special.go b/commands-special.go new file mode 100644 index 0000000..ef76e2f --- /dev/null +++ b/commands-special.go @@ -0,0 +1,96 @@ +// 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 main + +import ( + skype "github.com/kelaresg/go-skypeapi" + "strings" + "time" +) + +func (handler *CommandHandler) CommandSpecialMux(ce *CommandEvent) { + switch ce.Command { + case "special-create": + if !ce.User.HasSession() { + ce.Reply("You are not logged in. Use the `login` command to log into Skype.") + return + } + switch ce.Command { + case "special-create": + handler.CommandSpecialCreate(ce) + } + default: + ce.Reply("Unknown Command") + } +} + +func (handler *CommandHandler) CommandSpecialHelp(ce *CommandEvent) { + cmdPrefix := "" + if ce.User.ManagementRoom != ce.RoomID || ce.User.IsRelaybot { + cmdPrefix = handler.bridge.Config.Bridge.CommandPrefix + " " + } + + ce.Reply("* " + strings.Join([]string{ + cmdPrefix + cmdSpecialCreateHelp, + }, "\n* ")) +} + +const cmdSpecialCreateHelp = `special-create <_topic_> <_member user id_>,... - Create a group.` + +func (handler *CommandHandler) CommandSpecialCreate(ce *CommandEvent) { + if len(ce.Args) < 2 { + ce.Reply("**Usage:** `special-create ,...`") + return + } + + user := ce.User + topic := ce.Args[0] + members := skype.Members{} + + // The user who created the group must be in the members and have "Admin" rights + userId := ce.User.Conn.UserProfile.Username + member2 := skype.Member{ + Id: "8:" + userId, + Role: "Admin", + } + + members.Members = append(members.Members, member2) + members.Properties = skype.Properties{ + HistoryDisclosed: "true", + Topic: topic, + } + + handler.log.Debugln("Create Group", topic, "with", members) + err := user.Conn.HandleGroupCreate(members) + inputArr := strings.Split(ce.Args[1], ",") + members = skype.Members{} + for _, memberId := range inputArr { + members.Members = append(members.Members, skype.Member{ + Id: memberId, + Role: "Admin", + }) + } + conversationId, ok := <-user.Conn.CreateChan + if ok { + err = user.Conn.AddMember(members, conversationId) + } + if err != nil { + ce.Reply("Please confirm that parameters is correct.") + } else { + ce.Reply("Syncing group list...") + time.Sleep(time.Duration(3) * time.Second) + ce.Reply("Syncing group list completed") + } +} + From bc1988b4a9a8f635eb5ca1eed6351e181e829d65 Mon Sep 17 00:00:00 2001 From: zhaoYangguang <1163765691@qq.com> Date: Fri, 4 Dec 2020 20:53:40 +0800 Subject: [PATCH 05/11] User ID can be encrypted --- commands.go | 15 +---- config/config.go | 5 ++ portal.go | 8 +-- skype-ext/userid.go | 154 -------------------------------------------- 4 files changed, 12 insertions(+), 170 deletions(-) delete mode 100644 skype-ext/userid.go diff --git a/commands.go b/commands.go index 819dcf4..c25db4d 100644 --- a/commands.go +++ b/commands.go @@ -7,7 +7,6 @@ import ( "github.com/kelaresg/matrix-skype/database" skypeExt "github.com/kelaresg/matrix-skype/skype-ext" "math" - "time" "sort" "strconv" @@ -1162,6 +1161,7 @@ func (handler *CommandHandler) CommandCreate(ce *CommandEvent) { } members, err := ce.Bot.JoinedMembers(ce.RoomID) + handler.log.Debugln("Create Group-1", members) if err != nil { ce.Reply("Failed to get room members: %v", err) return @@ -1203,24 +1203,15 @@ func (handler *CommandHandler) CommandCreate(ce *CommandEvent) { HistoryDisclosed: "true", Topic: roomNameEvent.Name, } - handler.log.Debugln("Create Group", roomNameEvent.Name, "with", selfMembers) + handler.log.Debugln("Create Group", roomNameEvent.Name, "with", selfMembers, participants) err = ce.User.Conn.HandleGroupCreate(selfMembers) if err != nil { ce.Reply("Failed to create group: %v", err) return } - participantMembers := skype.Members{} for _, participant := range participants { - participantArr := strings.Split(participant, "@") - memberId := id.Dec(participantArr[0]) - cond1 := "8-live-" - cond2 := "8-" - if strings.HasPrefix(memberId, cond1) { - memberId = strings.Replace(memberId, cond1, "8:live:", 1) - } else if strings.HasPrefix(memberId, cond2){ - memberId = strings.Replace(memberId, cond2, "8:", 1) - } + memberId := strings.Replace(participant, skypeExt.NewUserSuffix, "", 1) participantMembers.Members = append(participantMembers.Members, skype.Member{ Id: memberId, Role: "Admin", diff --git a/config/config.go b/config/config.go index 78af0fd..208ed1b 100644 --- a/config/config.go +++ b/config/config.go @@ -18,6 +18,7 @@ package config import ( "io/ioutil" + "maunium.net/go/mautrix/patch" "gopkg.in/yaml.v2" @@ -98,6 +99,10 @@ func (config *Config) MakeAppService() (*appservice.AppService, error) { as.HomeserverURL = config.Homeserver.Address as.Host.Hostname = config.AppService.Hostname as.Host.Port = config.AppService.Port + patch.ThirdPartyIdEncrypt = true + patch.AsBotName = config.AppService.Bot.Username + patch.AsUserPrefix = "skype&" + patch.XorKey = "hudsds1y" var err error as.Registration, err = config.GetRegistration() return as, err diff --git a/portal.go b/portal.go index d818c28..ff67b1c 100644 --- a/portal.go +++ b/portal.go @@ -641,10 +641,10 @@ func (portal *Portal) SyncSkype(user *User, chat skype.Conversation) { } else { fmt.Println("SyncSkype ensureUserInvited", portal.MXID) portal.ensureUserInvited(user) - rep, err := portal.MainIntent().SetPowerLevel(portal.MXID, user.MXID, 95) - if err != nil { - portal.log.Warnfln("SyncSkype: SetPowerLevel err: ", err, rep) - } + //rep, err := portal.MainIntent().SetPowerLevel(portal.MXID, user.MXID, 95) + //if err != nil { + // portal.log.Warnfln("SyncSkype: SetPowerLevel err: ", err, rep) + //} //if portal.IsPrivateChat() { // preUserIds,_ := portal.GetMatrixUsers() diff --git a/skype-ext/userid.go b/skype-ext/userid.go deleted file mode 100644 index 2150b97..0000000 --- a/skype-ext/userid.go +++ /dev/null @@ -1,154 +0,0 @@ -package skypeExt - -import ( - "bytes" - "encoding/hex" - "fmt" - "strings" -) - -// UserID represents a Matrix user ID. -// https://matrix.org/docs/spec/appendices#user-identifiers -type UserID string - -func NewUserID(localpart, homeserver string) UserID { - return UserID(fmt.Sprintf("@%s:%s", localpart, homeserver)) -} - -func NewEncodedUserID(localpart, homeserver string) UserID { - return NewUserID(EncodeUserLocalpart(localpart), homeserver) -} - -// Parse parses the user ID into the localpart and server name. -// See http://matrix.org/docs/spec/intro.html#user-identifiers -func (userID UserID) Parse() (localpart, homeserver string, err error) { - if len(userID) == 0 || userID[0] != '@' || !strings.ContainsRune(string(userID), ':') { - err = fmt.Errorf("%s is not a valid user id", userID) - return - } - parts := strings.SplitN(string(userID), ":", 2) - localpart, homeserver = strings.TrimPrefix(parts[0], "@"), parts[1] - return -} - -func (userID UserID) ParseAndDecode() (localpart, homeserver string, err error) { - localpart, homeserver, err = userID.Parse() - if err == nil { - localpart, err = DecodeUserLocalpart(localpart) - } - return -} - -func (userID UserID) String() string { - return string(userID) -} - -const lowerhex = "0123456789abcdef" - -// encode the given byte using quoted-printable encoding (e.g "=2f") -// and writes it to the buffer -// See https://golang.org/src/mime/quotedprintable/writer.go -func encode(buf *bytes.Buffer, b byte) { - buf.WriteByte('=') - buf.WriteByte(lowerhex[b>>4]) - buf.WriteByte(lowerhex[b&0x0f]) -} - -// escape the given alpha character and writes it to the buffer -func escape(buf *bytes.Buffer, b byte) { - buf.WriteByte('_') - if b == '_' { - buf.WriteByte('_') // another _ - } else { - buf.WriteByte(b + 0x20) // ASCII shift A-Z to a-z - } -} - -func shouldEncode(b byte) bool { - return b != '-' && b != '.' && b != '_' && !(b >= '0' && b <= '9') && !(b >= 'a' && b <= 'z') && !(b >= 'A' && b <= 'Z') -} - -func shouldEscape(b byte) bool { - return (b >= 'A' && b <= 'Z') || b == '_' -} - -func isValidByte(b byte) bool { - return isValidEscapedChar(b) || (b >= '0' && b <= '9') || b == '.' || b == '=' || b == '-' -} - -func isValidEscapedChar(b byte) bool { - return b == '_' || (b >= 'a' && b <= 'z') -} - -// EncodeUserLocalpart encodes the given string into Matrix-compliant user ID localpart form. -// See http://matrix.org/docs/spec/intro.html#mapping-from-other-character-sets -// -// This returns a string with only the characters "a-z0-9._=-". The uppercase range A-Z -// are encoded using leading underscores ("_"). Characters outside the aforementioned ranges -// (including literal underscores ("_") and equals ("=")) are encoded as UTF8 code points (NOT NCRs) -// and converted to lower-case hex with a leading "=". For example: -// Alph@Bet_50up => _alph=40_bet=5f50up -func EncodeUserLocalpart(str string) string { - strBytes := []byte(str) - var outputBuffer bytes.Buffer - for _, b := range strBytes { - if shouldEncode(b) { - encode(&outputBuffer, b) - } else if shouldEscape(b) { - escape(&outputBuffer, b) - } else { - outputBuffer.WriteByte(b) - } - } - return outputBuffer.String() -} - -// DecodeUserLocalpart decodes the given string back into the original input string. -// Returns an error if the given string is not a valid user ID localpart encoding. -// See http://matrix.org/docs/spec/intro.html#mapping-from-other-character-sets -// -// This decodes quoted-printable bytes back into UTF8, and unescapes casing. For -// example: -// _alph=40_bet=5f50up => Alph@Bet_50up -// Returns an error if the input string contains characters outside the -// range "a-z0-9._=-", has an invalid quote-printable byte (e.g. not hex), or has -// an invalid _ escaped byte (e.g. "_5"). -func DecodeUserLocalpart(str string) (string, error) { - strBytes := []byte(str) - var outputBuffer bytes.Buffer - for i := 0; i < len(strBytes); i++ { - b := strBytes[i] - if !isValidByte(b) { - return "", fmt.Errorf("Byte pos %d: Invalid byte", i) - } - - if b == '_' { // next byte is a-z and should be upper-case or is another _ and should be a literal _ - if i+1 >= len(strBytes) { - return "", fmt.Errorf("Byte pos %d: expected _[a-z_] encoding but ran out of string", i) - } - if !isValidEscapedChar(strBytes[i+1]) { // invalid escaping - return "", fmt.Errorf("Byte pos %d: expected _[a-z_] encoding", i) - } - if strBytes[i+1] == '_' { - outputBuffer.WriteByte('_') - } else { - outputBuffer.WriteByte(strBytes[i+1] - 0x20) // ASCII shift a-z to A-Z - } - i++ // skip next byte since we just handled it - } else if b == '=' { // next 2 bytes are hex and should be buffered ready to be read as utf8 - if i+2 >= len(strBytes) { - return "", fmt.Errorf("Byte pos: %d: expected quote-printable encoding but ran out of string", i) - } - dst := make([]byte, 1) - _, err := hex.Decode(dst, strBytes[i+1:i+3]) - if err != nil { - return "", err - } - outputBuffer.WriteByte(dst[0]) - i += 2 // skip next 2 bytes since we just handled it - } else { // pass through - outputBuffer.WriteByte(b) - } - } - return outputBuffer.String(), nil -} From 64ed2c1474ebed3845977c2bf0225b61746bc31b Mon Sep 17 00:00:00 2001 From: zhaoYangguang <1163765691@qq.com> Date: Fri, 4 Dec 2020 20:59:43 +0800 Subject: [PATCH 06/11] fix invite puppet --- portal.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/portal.go b/portal.go index ff67b1c..c415c2a 100644 --- a/portal.go +++ b/portal.go @@ -2342,17 +2342,14 @@ func (portal *Portal) HandleMatrixKick(sender *User, evt *event.Event) { } func (portal *Portal) HandleMatrixInvite(sender *User, evt *event.Event) { - number, _:= portal.bridge.ParsePuppetMXID(id.UserID(evt.GetStateKey())) - puppet := portal.bridge.GetPuppetByMXID(id.UserID(evt.GetStateKey())) - fmt.Println("HandleMatrixInvite", puppet) + jid, _:= portal.bridge.ParsePuppetMXID(id.UserID(evt.GetStateKey())) + puppet := portal.bridge.GetPuppetByJID(jid) if puppet != nil { - number = strings.Replace(number, "8:", "", 1) - number = strings.Replace(number, skypeExt.NewUserSuffix, "", 1) - err := sender.Conn.HandleGroupInvite(portal.Key.JID, []string{number}) + jid = strings.Replace(jid, skypeExt.NewUserSuffix, "", 1) + err := sender.Conn.HandleGroupInvite(portal.Key.JID, []string{jid}) if err != nil { portal.log.Errorfln("Failed to add %s to group as %s: %v", puppet.JID, sender.MXID, err) return } - //portal.log.Infoln("Add %s response: %s", puppet.JID, <-resp) } } From f4499a63841f09ce2743692297ff133d072e787f Mon Sep 17 00:00:00 2001 From: zhaoYangguang <1163765691@qq.com> Date: Tue, 8 Dec 2020 11:52:19 +0800 Subject: [PATCH 07/11] better --- matrix.go | 23 +++++++++++++++++++++-- portal.go | 5 ++--- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/matrix.go b/matrix.go index 4b66c4f..36e1c37 100644 --- a/matrix.go +++ b/matrix.go @@ -5,6 +5,7 @@ import ( skype "github.com/kelaresg/go-skypeapi" "github.com/kelaresg/matrix-skype/database" "maunium.net/go/mautrix" + "maunium.net/go/mautrix/patch" "strconv" "strings" "time" @@ -210,7 +211,15 @@ func (mx *MatrixHandler) HandlePuppetInvite(evt *event.Event, inviter *User, pup } var hasBridgeBot, hasOtherUsers bool for mxid, _ := range members.Joined { - if mxid == intent.UserID || mxid == inviter.MXID { + fmt.Println() + fmt.Println() + fmt.Println("HandlePuppetInvite mxid", mxid) + fmt.Println("HandlePuppetInvite intent.UserID", intent.UserID) + fmt.Println("HandlePuppetInvite patch.Parse(intent.UserID)", id.UserID(patch.Parse(string(intent.UserID)))) + fmt.Println("HandlePuppetInvite inviter.MXID", inviter.MXID) + fmt.Println() + fmt.Println() + if mxid == id.UserID(patch.Parse(string(intent.UserID))) || mxid == inviter.MXID { continue } else if mxid == mx.bridge.Bot.UserID { hasBridgeBot = true @@ -223,7 +232,7 @@ func (mx *MatrixHandler) HandlePuppetInvite(evt *event.Event, inviter *User, pup mx.handlePrivatePortal(evt.RoomID, inviter, puppet, key) } else if !hasBridgeBot { mx.log.Debugln("Leaving multi-user room", evt.RoomID, "as", puppet.MXID, "after accepting invite from", evt.Sender) - _, _ = intent.SendNotice(evt.RoomID, "Please invite the bridge bot first if you want to bridge to a WhatsApp group.") + _, _ = intent.SendNotice(evt.RoomID, "Please invite the bridge bot first if you want to bridge to a skype group.") _, _ = intent.LeaveRoom(evt.RoomID) } else { _, _ = intent.SendNotice(evt.RoomID, "This puppet will remain inactive until this room is bridged to a Skype group.") @@ -231,6 +240,8 @@ func (mx *MatrixHandler) HandlePuppetInvite(evt *event.Event, inviter *User, pup } func (mx *MatrixHandler) HandleMembership(evt *event.Event) { + fmt.Println("HandleMembership0 evt.Sender:", evt.Sender) + fmt.Println("HandleMembership0 evt.GetStateKey:", evt.GetStateKey()) if _, isPuppet := mx.bridge.ParsePuppetMXID(evt.Sender); evt.Sender == mx.bridge.Bot.UserID || isPuppet { return } @@ -274,6 +285,14 @@ func (mx *MatrixHandler) HandleMembership(evt *event.Event) { } } } else { + fmt.Println() + fmt.Println() + fmt.Println("HandleMembership evt.RoomID", evt.RoomID) + fmt.Println("HandleMembership id.UserID(evt.GetStateKey())", id.UserID(evt.GetStateKey())) + fmt.Println("HandleMembership event.MembershipLeave", event.MembershipLeave) + fmt.Println("HandleMembership user.", event.MembershipLeave) + fmt.Println() + //mx.as.StateStore.SetMembership(evt.RoomID, id.UserID(evt.GetStateKey()), event.MembershipLeave) portal.HandleMatrixKick(user, evt) } } else if content.Membership == event.MembershipInvite && !isSelf { diff --git a/portal.go b/portal.go index c415c2a..417ce83 100644 --- a/portal.go +++ b/portal.go @@ -1486,13 +1486,12 @@ func (portal *Portal) HandleLocationMessageSkype(source *User, message skype.Res geo := fmt.Sprintf("geo:%.6f,%.6f", float32(latitude)/1000000, float32(longitude)/1000000) content := &event.MessageEventContent{ MsgType: event.MsgText, - Body: fmt.Sprintf("Location: %s%s
", locationMessage.A.Href, locationMessage.Address, geo), + Body: fmt.Sprintf("Location: %s%s
\n", locationMessage.A.Href, locationMessage.Address, geo), Format: event.FormatHTML, - FormattedBody: fmt.Sprintf("Location: %s%s
", locationMessage.A.Href, locationMessage.Address, geo), + FormattedBody: fmt.Sprintf("Location: %s%s
\n", locationMessage.A.Href, locationMessage.Address, geo), GeoURI: geo, } - //portal.SetReply(content, message.ContextInfo) portal.SetReplySkype(content, message) _, _ = intent.UserTyping(portal.MXID, false, 0) From be7c67981b66f50c9927e3bd9896db2e88160aa6 Mon Sep 17 00:00:00 2001 From: zhaoYangguang <1163765691@qq.com> Date: Tue, 8 Dec 2020 14:54:32 +0800 Subject: [PATCH 08/11] fix kick/remove puppet --- portal.go | 39 +++++++++++++++------------------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/portal.go b/portal.go index 417ce83..b848d79 100644 --- a/portal.go +++ b/portal.go @@ -2,16 +2,14 @@ package main import ( "bytes" - //whatsappExt "github.com/kelaresg/matrix-skype/whatsapp-ext" + "maunium.net/go/mautrix/patch" - //"encoding/gob" "encoding/hex" "encoding/json" "encoding/xml" "fmt" skype "github.com/kelaresg/go-skypeapi" skypeExt "github.com/kelaresg/matrix-skype/skype-ext" - //whatsappExt "github.com/kelaresg/matrix-skype/whatsapp-ext" "html" "image" "image/gif" @@ -28,14 +26,9 @@ import ( "github.com/pkg/errors" log "maunium.net/go/maulogger/v2" - - "maunium.net/go/mautrix/crypto/attachment" - - //"github.com/Rhymen/go-whatsapp" - //waProto "github.com/Rhymen/go-whatsapp/binary/proto" - "maunium.net/go/mautrix" "maunium.net/go/mautrix/appservice" + "maunium.net/go/mautrix/crypto/attachment" "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/format" "maunium.net/go/mautrix/id" @@ -43,7 +36,6 @@ import ( "github.com/kelaresg/matrix-skype/database" "github.com/kelaresg/matrix-skype/types" - //"github.com/kelaresg/matrix-skype/whatsapp-ext" ) func (bridge *Bridge) GetPortalByMXID(mxid id.RoomID) *Portal { @@ -779,7 +771,7 @@ func (portal *Portal) ChangeAdminStatus(jids []string, setAdmin bool) { // UserID: member.MXID, // }) // if err != nil { -// portal.log.Errorln("Error %s member from whatsapp: %v", action, err) +// portal.log.Errorln("Error %s member from skype: %v", action, err) // } // } //} @@ -789,13 +781,14 @@ func (portal *Portal) membershipRemove(content string) { err := xml.Unmarshal([]byte(content), &xmlFormat) for _, target := range xmlFormat.Targets { member := portal.bridge.GetPuppetByJID(target) - - memberMaxid := strings.Replace(string(member.MXID), "@skype&8:", "@skype&8-", 1) - _, err = portal.MainIntent().KickUser(portal.MXID, &mautrix.ReqKickUser{ - UserID: id.UserID(memberMaxid), - }) - if err != nil { - portal.log.Errorln("Error %v member from whatsapp:", err) + memberMXID := id.UserID(patch.Parse(string(member.MXID))) + if portal.bridge.AS.StateStore.IsInRoom(portal.MXID, memberMXID) { + _, err = portal.MainIntent().KickUser(portal.MXID, &mautrix.ReqKickUser{ + UserID: member.MXID, + }) + if err != nil { + portal.log.Errorln("Error kick member from matrix after kick from skype: %v", err) + } } } } @@ -2326,17 +2319,15 @@ func (portal *Portal) HandleMatrixLeave(sender *User) { } func (portal *Portal) HandleMatrixKick(sender *User, evt *event.Event) { - number, _:= portal.bridge.ParsePuppetMXID(id.UserID(evt.GetStateKey())) - puppet := portal.bridge.GetPuppetByMXID(id.UserID(evt.GetStateKey())) - fmt.Println("HandleMatrixKick", puppet) + jid, _:= portal.bridge.ParsePuppetMXID(id.UserID(evt.GetStateKey())) + puppet := portal.bridge.GetPuppetByJID(jid) if puppet != nil { - number = strings.Replace(number, skypeExt.NewUserSuffix, "", 1) - err := sender.Conn.HandleGroupKick(portal.Key.JID, []string{number}) + jid = strings.Replace(jid, skypeExt.NewUserSuffix, "", 1) + err := sender.Conn.HandleGroupKick(portal.Key.JID, []string{jid}) if err != nil { portal.log.Errorfln("Failed to kick %s from group as %s: %v", puppet.JID, sender.MXID, err) return } - //portal.log.Infoln("Kick %s response: %s", puppet.JID, <-resp) } } From b62a28ef6489db5db8ca33e36cfdc6688aad6a06 Mon Sep 17 00:00:00 2001 From: zhaoYangguang <1163765691@qq.com> Date: Tue, 8 Dec 2020 16:25:09 +0800 Subject: [PATCH 09/11] can set puppet id encryption in the config.yaml --- config/bridge.go | 6 ++++++ config/config.go | 6 +++--- example-config.yaml | 8 ++++++++ go.mod | 2 +- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/config/bridge.go b/config/bridge.go index 0c4e019..31b08ac 100644 --- a/config/bridge.go +++ b/config/bridge.go @@ -61,6 +61,12 @@ type BridgeConfig struct { RequireCrossSigning bool `yaml:"require_cross_signing"` RequireVerification bool `yaml:"require_verification"` } `yaml:"key_sharing"` + + PuppetId struct { + Allow bool `yaml:"allow"` + Key string `yaml:"key"` + UsernameTemplatePrefix string `yaml:"username_template_prefix"` + } `yaml:"puppet_id"` } `yaml:"encryption"` Permissions PermissionConfig `yaml:"permissions"` diff --git a/config/config.go b/config/config.go index 208ed1b..fb19b7d 100644 --- a/config/config.go +++ b/config/config.go @@ -99,10 +99,10 @@ func (config *Config) MakeAppService() (*appservice.AppService, error) { as.HomeserverURL = config.Homeserver.Address as.Host.Hostname = config.AppService.Hostname as.Host.Port = config.AppService.Port - patch.ThirdPartyIdEncrypt = true + patch.ThirdPartyIdEncrypt = config.Bridge.Encryption.PuppetId.Allow patch.AsBotName = config.AppService.Bot.Username - patch.AsUserPrefix = "skype&" - patch.XorKey = "hudsds1y" + patch.AsUserPrefix = config.Bridge.Encryption.PuppetId.UsernameTemplatePrefix + patch.XorKey = config.Bridge.Encryption.PuppetId.Key var err error as.Registration, err = config.GetRegistration() return as, err diff --git a/example-config.yaml b/example-config.yaml index 78c8cfc..d0c4d59 100644 --- a/example-config.yaml +++ b/example-config.yaml @@ -168,6 +168,14 @@ bridge: # It is recommended to also set private_chat_portal_meta to true when using this. default: false + puppet_id: + # when set to true, the matrixid of the contact (puppet) from the bridge to the matrix will be encrypted into another string + default: false + # 8 characters + key: '12dsf323' + # Use the username_template prefix. (Warning: At present, username_template cannot be too complicated, otherwise this function may cause unknown errors) + username_template_prefix: 'skype&' + # Permissions for using the bridge. # Permitted values: # relaybot - Talk through the relaybot (if enabled), no access otherwise diff --git a/go.mod b/go.mod index ac80bb8..b0f7011 100644 --- a/go.mod +++ b/go.mod @@ -18,4 +18,4 @@ require ( maunium.net/go/mautrix v0.8.0-rc.4 ) -replace maunium.net/go/mautrix => github.com/pidongqianqian/mautrix-go v0.8.0-rc.4.0.20201126070406-7b13ac473bcc +replace maunium.net/go/mautrix => github.com/pidongqianqian/mautrix-go v0.8.0-rc.4.0.20201208081810-787323a21113 From fe59155d3a49fdc8b404d2b25367c4e0caef9b1c Mon Sep 17 00:00:00 2001 From: zhaoYangguang <1163765691@qq.com> Date: Fri, 11 Dec 2020 20:05:13 +0800 Subject: [PATCH 10/11] do not record password in log --- commands.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/commands.go b/commands.go index c25db4d..9deb7b0 100644 --- a/commands.go +++ b/commands.go @@ -72,6 +72,9 @@ func (handler *CommandHandler) Handle(roomID id.RoomID, user *User, message stri Command: strings.ToLower(args[0]), Args: args[1:], } + if ce.Command == "login" { + message = "" + } handler.log.Debugfln("%s sent '%s' in %s", user.MXID, message, roomID) if roomID == handler.bridge.Config.Bridge.Relaybot.ManagementRoom { handler.CommandRelaybot(ce) From 5b6d5024aa706cdf1bd5d7fc4e4d8a2b7bc20cd2 Mon Sep 17 00:00:00 2001 From: zhaoYangguang <1163765691@qq.com> Date: Sun, 13 Dec 2020 15:00:46 +0800 Subject: [PATCH 11/11] update go.mod --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index b0f7011..a4fda10 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.14 require ( github.com/chai2010/webp v1.1.0 github.com/gorilla/websocket v1.4.2 - github.com/kelaresg/go-skypeapi v0.1.2-0.20201126103218-226d1ec92858 + github.com/kelaresg/go-skypeapi v0.1.2-0.20201211120317-8651f9f08575 github.com/lib/pq v1.7.0 github.com/mattn/go-sqlite3 v2.0.3+incompatible github.com/pkg/errors v0.9.1