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:
parent
69f4670ed0
commit
362e918cb6
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
75
crypto.go
75
crypto.go
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
2
main.go
2
main.go
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
15
portal.go
15
portal.go
|
@ -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 != "" {
|
||||||
|
|
|
@ -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
34
user.go
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue