update double puppet related logic, fix the issue user will rejion matrix room even if user has logout skype(bridge)

This commit is contained in:
zhaoYangguang 2021-12-09 17:27:06 +08:00
parent 69f4670ed0
commit 362e918cb6
10 changed files with 159 additions and 106 deletions

View File

@ -262,6 +262,13 @@ func (handler *CommandHandler) CommandLogout(ce *CommandEvent) {
Contacts: make(map[string]skype.Contact), Contacts: make(map[string]skype.Contact),
Chats: make(map[string]skype.Conversation), Chats: make(map[string]skype.Conversation),
} }
puppet := handler.bridge.GetPuppetByJID(ce.User.JID)
if puppet.CustomMXID != "" {
err := puppet.SwitchCustomMXID("", "")
if err != nil {
ce.User.log.Warnln("Failed to logout-matrix while logging out of WhatsApp:", err)
}
}
ce.Reply("Logged out successfully.") ce.Reply("Logged out successfully.")
if ce.User.Conn.Refresh != nil { if ce.User.Conn.Refresh != nil {
ce.User.Conn.Refresh <- -1 ce.User.Conn.Refresh <- -1

View File

@ -2,11 +2,12 @@ package config
import ( import (
"bytes" "bytes"
skype "github.com/kelaresg/go-skypeapi"
"strconv" "strconv"
"strings" "strings"
"text/template" "text/template"
skype "github.com/kelaresg/go-skypeapi"
"maunium.net/go/mautrix/event" "maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/id" "maunium.net/go/mautrix/id"
@ -41,11 +42,14 @@ type BridgeConfig struct {
SyncChatMaxAge uint64 `yaml:"sync_max_chat_age"` SyncChatMaxAge uint64 `yaml:"sync_max_chat_age"`
SyncWithCustomPuppets bool `yaml:"sync_with_custom_puppets"` SyncWithCustomPuppets bool `yaml:"sync_with_custom_puppets"`
LoginSharedSecret string `yaml:"login_shared_secret"`
InviteOwnPuppetForBackfilling bool `yaml:"invite_own_puppet_for_backfilling"` InviteOwnPuppetForBackfilling bool `yaml:"invite_own_puppet_for_backfilling"`
PrivateChatPortalMeta bool `yaml:"private_chat_portal_meta"` PrivateChatPortalMeta bool `yaml:"private_chat_portal_meta"`
DoublePuppetServerMap map[string]string `yaml:"double_puppet_server_map"`
DoublePuppetAllowDiscovery bool `yaml:"double_puppet_allow_discovery"`
LoginSharedSecretMap map[string]string `yaml:"login_shared_secret_map"`
WhatsappThumbnail bool `yaml:"whatsapp_thumbnail"` WhatsappThumbnail bool `yaml:"whatsapp_thumbnail"`
AllowUserInvite bool `yaml:"allow_user_invite"` AllowUserInvite bool `yaml:"allow_user_invite"`
@ -99,7 +103,6 @@ func (bc *BridgeConfig) setDefaults() {
bc.SyncChatMaxAge = 259200 bc.SyncChatMaxAge = 259200
bc.SyncWithCustomPuppets = true bc.SyncWithCustomPuppets = true
bc.LoginSharedSecret = ""
bc.InviteOwnPuppetForBackfilling = true bc.InviteOwnPuppetForBackfilling = true
bc.PrivateChatPortalMeta = false bc.PrivateChatPortalMeta = false

View File

@ -18,6 +18,8 @@ package config
import ( import (
"io/ioutil" "io/ioutil"
"maunium.net/go/mautrix/id"
"maunium.net/go/mautrix/patch" "maunium.net/go/mautrix/patch"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
@ -68,6 +70,12 @@ type Config struct {
Logging appservice.LogConfig `yaml:"logging"` Logging appservice.LogConfig `yaml:"logging"`
} }
func (config *Config) CanAutoDoublePuppet(userID id.UserID) bool {
_, homeserver, _ := userID.Parse()
_, hasSecret := config.Bridge.LoginSharedSecretMap[homeserver]
return hasSecret
}
func (config *Config) setDefaults() { func (config *Config) setDefaults() {
config.AppService.Database.MaxOpenConns = 20 config.AppService.Database.MaxOpenConns = 20
config.AppService.Database.MaxIdleConns = 2 config.AppService.Database.MaxIdleConns = 2

View File

@ -11,18 +11,18 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
//go:build cgo && !nocrypto
// +build cgo,!nocrypto // +build cgo,!nocrypto
package main package main
import ( import (
"crypto/hmac"
"crypto/sha512"
"encoding/hex"
"fmt" "fmt"
"runtime/debug"
"time" "time"
"github.com/pkg/errors" "github.com/lib/pq"
"maunium.net/go/maulogger/v2" "maunium.net/go/maulogger/v2"
"maunium.net/go/mautrix" "maunium.net/go/mautrix"
@ -48,13 +48,14 @@ type CryptoHelper struct {
baseLog maulogger.Logger baseLog maulogger.Logger
} }
func init() {
crypto.PostgresArrayWrapper = pq.Array
}
func NewCryptoHelper(bridge *Bridge) Crypto { func NewCryptoHelper(bridge *Bridge) Crypto {
if !bridge.Config.Bridge.Encryption.Allow { if !bridge.Config.Bridge.Encryption.Allow {
bridge.Log.Debugln("Bridge built with end-to-bridge encryption, but disabled in config") bridge.Log.Debugln("Bridge built with end-to-bridge encryption, but disabled in config")
return nil return nil
} else if bridge.Config.Bridge.LoginSharedSecret == "" {
bridge.Log.Warnln("End-to-bridge encryption enabled, but login_shared_secret not set")
return nil
} }
baseLog := bridge.Log.Sub("Crypto") baseLog := bridge.Log.Sub("Crypto")
return &CryptoHelper{ return &CryptoHelper{
@ -101,7 +102,8 @@ func (helper *CryptoHelper) allowKeyShare(device *crypto.DeviceIdentity, info ev
return &crypto.KeyShareRejection{Code: event.RoomKeyWithheldUnavailable, Reason: "Requested room is not a portal room"} return &crypto.KeyShareRejection{Code: event.RoomKeyWithheldUnavailable, Reason: "Requested room is not a portal room"}
} }
user := helper.bridge.GetUserByMXID(device.UserID) user := helper.bridge.GetUserByMXID(device.UserID)
if !user.IsInPortal(portal.Key) { // FIXME reimplement IsInPortal
if !user.Admin /*&& !user.IsInPortal(portal.Key)*/ {
helper.log.Debugfln("Rejecting key request for %s from %s/%s: user is not in portal", info.SessionID, device.UserID, device.DeviceID) helper.log.Debugfln("Rejecting key request for %s from %s/%s: user is not in portal", info.SessionID, device.UserID, device.DeviceID)
return &crypto.KeyShareRejection{Code: event.RoomKeyWithheldUnauthorized, Reason: "You're not in that portal"} return &crypto.KeyShareRejection{Code: event.RoomKeyWithheldUnauthorized, Reason: "You're not in that portal"}
} }
@ -128,14 +130,15 @@ func (helper *CryptoHelper) loginBot() (*mautrix.Client, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get supported login flows: %w", err) return nil, fmt.Errorf("failed to get supported login flows: %w", err)
} }
if !flows.HasFlow(mautrix.AuthTypeHalfyAppservice) { flow := flows.FirstFlowOfType(mautrix.AuthTypeAppservice, mautrix.AuthTypeHalfyAppservice)
if flow == nil {
return nil, fmt.Errorf("homeserver does not support appservice login") return nil, fmt.Errorf("homeserver does not support appservice login")
} }
// We set the API token to the AS token here to authenticate the appservice login // We set the API token to the AS token here to authenticate the appservice login
// It'll get overridden after the login // It'll get overridden after the login
client.AccessToken = helper.bridge.AS.Registration.AppToken client.AccessToken = helper.bridge.AS.Registration.AppToken
resp, err := client.Login(&mautrix.ReqLogin{ resp, err := client.Login(&mautrix.ReqLogin{
Type: mautrix.AuthTypeHalfyAppservice, Type: flow.Type,
Identifier: mautrix.UserIdentifier{Type: mautrix.IdentifierTypeUser, User: string(helper.bridge.AS.BotMXID())}, Identifier: mautrix.UserIdentifier{Type: mautrix.IdentifierTypeUser, User: string(helper.bridge.AS.BotMXID())},
DeviceID: deviceID, DeviceID: deviceID,
InitialDeviceDisplayName: "Skype Bridge", InitialDeviceDisplayName: "Skype Bridge",
@ -144,37 +147,7 @@ func (helper *CryptoHelper) loginBot() (*mautrix.Client, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to log in as bridge bot: %w", err) return nil, fmt.Errorf("failed to log in as bridge bot: %w", err)
} }
if len(deviceID) == 0 {
helper.store.DeviceID = resp.DeviceID helper.store.DeviceID = resp.DeviceID
}
return client, nil
}
func (helper *CryptoHelper) loginBotOld() (*mautrix.Client, error) {
deviceID := helper.store.FindDeviceID()
if len(deviceID) > 0 {
helper.log.Debugln("Found existing device ID for bot in database:", deviceID)
}
mac := hmac.New(sha512.New, []byte(helper.bridge.Config.Bridge.LoginSharedSecret))
mac.Write([]byte(helper.bridge.AS.BotMXID()))
client, err := mautrix.NewClient(helper.bridge.AS.HomeserverURL, "", "")
if err != nil {
return nil, err
}
resp, err := client.Login(&mautrix.ReqLogin{
Type: mautrix.AuthTypePassword,
Identifier: mautrix.UserIdentifier{Type: mautrix.IdentifierTypeUser, User: string(helper.bridge.AS.BotMXID())},
Password: hex.EncodeToString(mac.Sum(nil)),
DeviceID: deviceID,
InitialDeviceDisplayName: "Skype Bridge",
StoreCredentials: true,
})
if err != nil {
return nil, err
}
if len(deviceID) == 0 {
helper.store.DeviceID = resp.DeviceID
}
return client, nil return client, nil
} }
@ -203,15 +176,15 @@ func (helper *CryptoHelper) Encrypt(roomID id.RoomID, evtType event.Type, conten
helper.log.Debugfln("Got %v while encrypting event for %s, sharing group session and trying again...", err, roomID) helper.log.Debugfln("Got %v while encrypting event for %s, sharing group session and trying again...", err, roomID)
users, err := helper.store.GetRoomMembers(roomID) users, err := helper.store.GetRoomMembers(roomID)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to get room member list") return nil, fmt.Errorf("failed to get room member list: %w", err)
} }
err = helper.mach.ShareGroupSession(roomID, users) err = helper.mach.ShareGroupSession(roomID, users)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to share group session") return nil, fmt.Errorf("failed to share group session: %w", err)
} }
encrypted, err = helper.mach.EncryptMegolmEvent(roomID, evtType, &content) encrypted, err = helper.mach.EncryptMegolmEvent(roomID, evtType, &content)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to encrypt event after re-sharing group session") return nil, fmt.Errorf("failed to encrypt event after re-sharing group session: %w", err)
} }
} }
return encrypted, nil return encrypted, nil
@ -226,7 +199,23 @@ type cryptoSyncer struct {
} }
func (syncer *cryptoSyncer) ProcessResponse(resp *mautrix.RespSync, since string) error { func (syncer *cryptoSyncer) ProcessResponse(resp *mautrix.RespSync, since string) error {
done := make(chan struct{})
go func() {
defer func() {
if err := recover(); err != nil {
syncer.Log.Error("Processing sync response (%s) panicked: %v\n%s", since, err, debug.Stack())
}
done <- struct{}{}
}()
syncer.Log.Trace("Starting sync response handling (%s)", since)
syncer.ProcessSyncResponse(resp, since) syncer.ProcessSyncResponse(resp, since)
syncer.Log.Trace("Successfully handled sync response (%s)", since)
}()
select {
case <-done:
case <-time.After(30 * time.Second):
syncer.Log.Warn("Handling sync response (%s) is taking unusually long", since)
}
return nil return nil
} }

View File

@ -4,7 +4,7 @@ import (
"crypto/hmac" "crypto/hmac"
"crypto/sha512" "crypto/sha512"
"encoding/hex" "encoding/hex"
"strings" "fmt"
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -28,7 +28,7 @@ func (puppet *Puppet) SwitchCustomMXID(accessToken string, mxid id.UserID) error
puppet.CustomMXID = mxid puppet.CustomMXID = mxid
puppet.AccessToken = accessToken puppet.AccessToken = accessToken
err := puppet.StartCustomMXID() err := puppet.StartCustomMXID(false)
if err != nil { if err != nil {
return err return err
} }
@ -46,11 +46,17 @@ func (puppet *Puppet) SwitchCustomMXID(accessToken string, mxid id.UserID) error
} }
func (puppet *Puppet) loginWithSharedSecret(mxid id.UserID) (string, error) { func (puppet *Puppet) loginWithSharedSecret(mxid id.UserID) (string, error) {
mac := hmac.New(sha512.New, []byte(puppet.bridge.Config.Bridge.LoginSharedSecret)) _, homeserver, _ := mxid.Parse()
puppet.log.Debugfln("Logging into %s with shared secret", mxid)
mac := hmac.New(sha512.New, []byte(puppet.bridge.Config.Bridge.LoginSharedSecretMap[homeserver]))
mac.Write([]byte(mxid)) mac.Write([]byte(mxid))
resp, err := puppet.bridge.AS.BotClient().Login(&mautrix.ReqLogin{ client, err := puppet.bridge.newDoublePuppetClient(mxid, "")
Type: "m.login.password", if err != nil {
Identifier: mautrix.UserIdentifier{Type: "m.id.user", User: string(mxid)}, return "", fmt.Errorf("failed to create mautrix client to log in: %v", err)
}
resp, err := client.Login(&mautrix.ReqLogin{
Type: mautrix.AuthTypePassword,
Identifier: mautrix.UserIdentifier{Type: mautrix.IdentifierTypeUser, User: string(mxid)},
Password: hex.EncodeToString(mac.Sum(nil)), Password: hex.EncodeToString(mac.Sum(nil)),
DeviceID: "Skype Bridge", DeviceID: "Skype Bridge",
InitialDeviceDisplayName: "Skype Bridge", InitialDeviceDisplayName: "Skype Bridge",
@ -61,6 +67,36 @@ func (puppet *Puppet) loginWithSharedSecret(mxid id.UserID) (string, error) {
return resp.AccessToken, nil return resp.AccessToken, nil
} }
func (bridge *Bridge) newDoublePuppetClient(mxid id.UserID, accessToken string) (*mautrix.Client, error) {
_, homeserver, err := mxid.Parse()
if err != nil {
return nil, err
}
homeserverURL, found := bridge.Config.Bridge.DoublePuppetServerMap[homeserver]
if !found {
if homeserver == bridge.AS.HomeserverDomain {
homeserverURL = bridge.AS.HomeserverURL
} else if bridge.Config.Bridge.DoublePuppetAllowDiscovery {
resp, err := mautrix.DiscoverClientAPI(homeserver)
if err != nil {
return nil, fmt.Errorf("failed to find homeserver URL for %s: %v", homeserver, err)
}
homeserverURL = resp.Homeserver.BaseURL
bridge.Log.Debugfln("Discovered URL %s for %s to enable double puppeting for %s", homeserverURL, homeserver, mxid)
} else {
return nil, fmt.Errorf("double puppeting from %s is not allowed", homeserver)
}
}
client, err := mautrix.NewClient(homeserverURL, mxid, accessToken)
if err != nil {
return nil, err
}
client.Logger = bridge.AS.Log.Sub(mxid.String())
client.Client = bridge.AS.HTTPClient
client.DefaultHTTPRetries = bridge.AS.DefaultHTTPRetries
return client, nil
}
func (puppet *Puppet) newCustomIntent() (*appservice.IntentAPI, error) { func (puppet *Puppet) newCustomIntent() (*appservice.IntentAPI, error) {
if len(puppet.CustomMXID) == 0 { if len(puppet.CustomMXID) == 0 {
return nil, ErrNoCustomMXID return nil, ErrNoCustomMXID
@ -89,7 +125,7 @@ func (puppet *Puppet) clearCustomMXID() {
puppet.customUser = nil puppet.customUser = nil
} }
func (puppet *Puppet) StartCustomMXID() error { func (puppet *Puppet) StartCustomMXID(reloginOnFail bool) error {
if len(puppet.CustomMXID) == 0 { if len(puppet.CustomMXID) == 0 {
puppet.clearCustomMXID() puppet.clearCustomMXID()
return nil return nil
@ -101,21 +137,12 @@ func (puppet *Puppet) StartCustomMXID() error {
} }
resp, err := intent.Whoami() resp, err := intent.Whoami()
if err != nil { if err != nil {
// if strings.Index(err.Error(), "M_UNKNOWN_TOKEN (HTTP 401)") > -1 { if !reloginOnFail || (errors.Is(err, mautrix.MUnknownToken) && !puppet.tryRelogin(err, "initializing double puppeting")) {
// puppet.log.Debugln("StartCustomMXID UpdateAccessToken: ", puppet.MXID)
// if puppet.customUser != nil {
// err, _ = puppet.customUser.UpdateAccessToken(puppet)
// }
// }
if puppet.customUser != nil {
err, _ = puppet.updateCustomAccessTokenIfExpired(err, puppet.customUser)
}
if err != nil {
puppet.clearCustomMXID() puppet.clearCustomMXID()
return err return err
} }
} intent.AccessToken = puppet.AccessToken
if resp.UserID != puppet.CustomMXID { } else if resp.UserID != puppet.CustomMXID {
puppet.clearCustomMXID() puppet.clearCustomMXID()
return ErrMismatchingMXID return ErrMismatchingMXID
} }
@ -126,17 +153,6 @@ func (puppet *Puppet) StartCustomMXID() error {
return nil return nil
} }
func (puppet *Puppet) updateCustomAccessTokenIfExpired(err error, user *User) (newErr error, accessToken string) {
if user == nil {
return err, ""
}
puppet.log.Debugln("StartCustomMXID UpdateAccessToken: ", puppet.MXID)
if strings.Index(err.Error(), "M_UNKNOWN_TOKEN (HTTP 401)") > -1 {
return user.UpdateAccessToken(puppet)
}
return err, ""
}
func (puppet *Puppet) startSyncing() { func (puppet *Puppet) startSyncing() {
if !puppet.bridge.Config.Bridge.SyncWithCustomPuppets { if !puppet.bridge.Config.Bridge.SyncWithCustomPuppets {
return return
@ -249,9 +265,30 @@ func (puppet *Puppet) handleTypingEvent(portal *Portal, evt *event.Event) {
//} //}
} }
func (puppet *Puppet) tryRelogin(cause error, action string) bool {
if !puppet.bridge.Config.CanAutoDoublePuppet(puppet.CustomMXID) {
return false
}
puppet.log.Debugfln("Trying to relogin after '%v' while %s", cause, action)
accessToken, err := puppet.loginWithSharedSecret(puppet.CustomMXID)
if err != nil {
puppet.log.Errorfln("Failed to relogin after '%v' while %s: %v", cause, action, err)
return false
}
puppet.log.Infofln("Successfully relogined after '%v' while %s", cause, action)
puppet.AccessToken = accessToken
return true
}
func (puppet *Puppet) OnFailedSync(res *mautrix.RespSync, err error) (time.Duration, error) { func (puppet *Puppet) OnFailedSync(res *mautrix.RespSync, err error) (time.Duration, error) {
puppet.log.Warnln("Sync error:", err) puppet.log.Warnln("Sync error:", err)
err, _ = puppet.updateCustomAccessTokenIfExpired(err, puppet.customUser) if errors.Is(err, mautrix.MUnknownToken) {
if !puppet.tryRelogin(err, "syncing") {
return 0, err
}
puppet.customIntent.AccessToken = puppet.AccessToken
return 0, nil
}
return 10 * time.Second, err return 10 * time.Second, err
} }

View File

@ -129,12 +129,19 @@ bridge:
# Whether or not to sync with custom puppets to receive EDUs that # Whether or not to sync with custom puppets to receive EDUs that
# are not normally sent to appservices. # are not normally sent to appservices.
sync_with_custom_puppets: true sync_with_custom_puppets: true
# Servers to always allow double puppeting from
double_puppet_server_map:
example.com: https://example.com
# Allow using double puppeting from any server with a valid client .well-known file.
double_puppet_allow_discovery: false
# Shared secret for https://github.com/devture/matrix-synapse-shared-secret-auth # Shared secret for https://github.com/devture/matrix-synapse-shared-secret-auth
# #
# If set, custom puppets will be enabled automatically for local users # If set, custom puppets will be enabled automatically for local users
# instead of users having to find an access token and run `login-matrix` # instead of users having to find an access token and run `login-matrix`
# manually. # manually.
login_shared_secret: null login_shared_secret_map:
example.com: foobar
# Whether or not to invite own Skype user's Matrix puppet into private # Whether or not to invite own Skype user's Matrix puppet into private
# chat portals when backfilling if needed. # chat portals when backfilling if needed.

View File

@ -323,7 +323,7 @@ func (bridge *Bridge) StartUsers() {
for _, loopuppet := range bridge.GetAllPuppetsWithCustomMXID() { for _, loopuppet := range bridge.GetAllPuppetsWithCustomMXID() {
go func(puppet *Puppet) { go func(puppet *Puppet) {
puppet.log.Debugln("Starting custom puppet", puppet.CustomMXID) puppet.log.Debugln("Starting custom puppet", puppet.CustomMXID)
err := puppet.StartCustomMXID() err := puppet.StartCustomMXID(true)
if err != nil { if err != nil {
puppet.log.Errorln("Failed to start custom puppet:", err) puppet.log.Errorln("Failed to start custom puppet:", err)
} }

View File

@ -346,8 +346,9 @@ func (portal *Portal) getMessageIntentSkype(user *User, info skype.Resource) *ap
return portal.bridge.GetPuppetByJID(info.SendId + skypeExt.NewUserSuffix).IntentFor(portal) return portal.bridge.GetPuppetByJID(info.SendId + skypeExt.NewUserSuffix).IntentFor(portal)
} }
func (portal *Portal) handlePrivateChatFromMe(fromMe bool) func() { func (portal *Portal) handlePrivateChatFromMe(user *User, fromMe bool) func() {
if portal.IsPrivateChat() && fromMe && len(portal.bridge.Config.Bridge.LoginSharedSecret) == 0 { _, homeserver, _ := user.MXID.Parse()
if portal.IsPrivateChat() && fromMe && len(portal.bridge.Config.Bridge.LoginSharedSecretMap[homeserver]) == 0 {
var privateChatPuppet *Puppet var privateChatPuppet *Puppet
var privateChatPuppetInvited bool var privateChatPuppetInvited bool
privateChatPuppet = portal.bridge.GetPuppetByJID(portal.Key.Receiver) privateChatPuppet = portal.bridge.GetPuppetByJID(portal.Key.Receiver)
@ -378,10 +379,9 @@ func (portal *Portal) startHandlingSkype(source *User, info skype.Resource) (*ap
} else { } else {
portal.log.Debugfln("Starting handling of %s (ts: %d)", info.Id, info.Timestamp) portal.log.Debugfln("Starting handling of %s (ts: %d)", info.Id, info.Timestamp)
portal.lastMessageTs = uint64(info.Timestamp) portal.lastMessageTs = uint64(info.Timestamp)
return portal.getMessageIntentSkype(source, info), portal.handlePrivateChatFromMe(info.GetFromMe(source.Conn.Conn)) return portal.getMessageIntentSkype(source, info), portal.handlePrivateChatFromMe(source, info.GetFromMe(source.Conn.Conn))
} }
fmt.Println() portal.log.Debugfln("startHandlingSkype: %+v", "but nil")
fmt.Printf("portal startHandling: %+v", "but nil")
return nil, nil return nil, nil
} }
@ -945,7 +945,8 @@ func (portal *Portal) beginBackfill() func() {
portal.privateChatBackfillInvitePuppet = nil portal.privateChatBackfillInvitePuppet = nil
portal.backfillLock.Unlock() portal.backfillLock.Unlock()
if privateChatPuppet != nil && privateChatPuppetInvited { if privateChatPuppet != nil && privateChatPuppetInvited {
if len(portal.bridge.Config.Bridge.LoginSharedSecret) > 0 { _, homeserver, _ := privateChatPuppet.MXID.Parse()
if len(portal.bridge.Config.Bridge.LoginSharedSecretMap[homeserver]) > 0 {
_, _ = privateChatPuppet.DefaultIntent().LeaveRoom(portal.MXID) _, _ = privateChatPuppet.DefaultIntent().LeaveRoom(portal.MXID)
} }
} }
@ -1512,7 +1513,7 @@ func (portal *Portal) trySendMessage(intent *appservice.IntentAPI, eventType eve
resp, err = portal.sendMessage(intent, eventType, content, message.Timestamp*1000) resp, err = portal.sendMessage(intent, eventType, content, message.Timestamp*1000)
if err != nil { if err != nil {
portal.log.Errorfln("Failed to handle message %s: %v", message.Id, err) portal.log.Errorfln("Failed to handle message %s: %v", message.Id, err)
if strings.Index(err.Error(), "M_UNKNOWN_TOKEN (HTTP 401)") > -1 { if errors.Is(err, mautrix.MUnknownToken) {
puppet := source.bridge.GetPuppetByJID(source.JID) puppet := source.bridge.GetPuppetByJID(source.JID)
err, accessToken := source.UpdateAccessToken(puppet) err, accessToken := source.UpdateAccessToken(puppet)
if err == nil && accessToken != "" { if err == nil && accessToken != "" {

View File

@ -6,6 +6,7 @@ import (
skypeExt "github.com/kelaresg/matrix-skype/skype-ext" skypeExt "github.com/kelaresg/matrix-skype/skype-ext"
"net/http" "net/http"
"regexp" "regexp"
"sync"
"strings" "strings"
log "maunium.net/go/maulogger/v2" log "maunium.net/go/maulogger/v2"
@ -159,6 +160,8 @@ type Puppet struct {
customIntent *appservice.IntentAPI customIntent *appservice.IntentAPI
customTypingIn map[id.RoomID]bool customTypingIn map[id.RoomID]bool
customUser *User customUser *User
syncLock sync.Mutex
} }
func (puppet *Puppet) PhoneNumber() string { func (puppet *Puppet) PhoneNumber() string {

34
user.go
View File

@ -445,34 +445,32 @@ func (user *User) PostLogin() {
} }
func (user *User) tryAutomaticDoublePuppeting() { func (user *User) tryAutomaticDoublePuppeting() {
fmt.Println("tryAutomaticDoublePuppeting") if !user.bridge.Config.CanAutoDoublePuppet(user.MXID) {
if len(user.bridge.Config.Bridge.LoginSharedSecret) == 0 {
fmt.Println("tryAutomaticDoublePuppeting-1", user.bridge.Config.Bridge.LoginSharedSecret)
// Automatic login not enabled
return
} else if _, homeserver, _ := user.MXID.Parse(); homeserver != user.bridge.Config.Homeserver.Domain {
fmt.Println("tryAutomaticDoublePuppeting-2", user.MXID)
fmt.Println("tryAutomaticDoublePuppeting-21", homeserver)
fmt.Println("tryAutomaticDoublePuppeting--3", user.bridge.Config.Homeserver.Domain)
// user is on another homeserver
return return
} }
fmt.Println("tryAutomaticDoublePuppeting1") user.log.Debugln("Checking if double puppeting needs to be enabled")
puppet := user.bridge.GetPuppetByJID(user.JID) puppet := user.bridge.GetPuppetByJID(user.JID)
if len(puppet.CustomMXID) > 0 { if len(puppet.CustomMXID) > 0 {
user.log.Debugln("User already has double-puppeting enabled")
// Custom puppet already enabled // Custom puppet already enabled
return return
} }
fmt.Println("tryAutomaticDoublePuppeting2", user.MXID) accessToken, err := puppet.loginWithSharedSecret(user.MXID)
_, _ = user.UpdateAccessToken(puppet) if err != nil {
user.log.Warnln("Failed to login with shared secret:", err)
return
}
err = puppet.SwitchCustomMXID(accessToken, user.MXID)
if err != nil {
puppet.log.Warnln("Failed to switch to auto-logined custom puppet:", err)
return
}
user.log.Infoln("Successfully automatically enabled custom puppet")
} }
func (user *User) UpdateAccessToken(puppet *Puppet) (err error, accessToken string) { func (user *User) UpdateAccessToken(puppet *Puppet) (err error, accessToken string) {
if len(user.bridge.Config.Bridge.LoginSharedSecret) == 0 { if !puppet.bridge.Config.CanAutoDoublePuppet(user.MXID) {
return errors.New("you didn't set LoginSharedSecret"), "" return errors.New("you didn't set LoginSharedSecret or user is on another homeServer"), ""
} else if _, homeserver, _ := user.MXID.Parse(); homeserver != user.bridge.Config.Homeserver.Domain {
// user is on another homeserver
return errors.New("user is on another homeServer"), ""
} }
accessToken, err = puppet.loginWithSharedSecret(user.MXID) accessToken, err = puppet.loginWithSharedSecret(user.MXID)
if err != nil { if err != nil {