-
-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move double puppeting login code to mautrix-go
- Loading branch information
Showing
6 changed files
with
55 additions
and
182 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,170 +1,72 @@ | ||
package main | ||
|
||
import ( | ||
"crypto/hmac" | ||
"crypto/sha512" | ||
"encoding/hex" | ||
"errors" | ||
"fmt" | ||
|
||
"maunium.net/go/mautrix" | ||
"maunium.net/go/mautrix/appservice" | ||
"maunium.net/go/mautrix/id" | ||
) | ||
|
||
var ( | ||
ErrNoCustomMXID = errors.New("no custom mxid set") | ||
ErrMismatchingMXID = errors.New("whoami result does not match custom mxid") | ||
) | ||
|
||
func (br *DiscordBridge) newDoublePuppetClient(mxid id.UserID, accessToken string) (*mautrix.Client, error) { | ||
_, homeserver, err := mxid.Parse() | ||
func (puppet *Puppet) SwitchCustomMXID(accessToken string, mxid id.UserID) error { | ||
puppet.CustomMXID = mxid | ||
puppet.AccessToken = accessToken | ||
puppet.Update() | ||
err := puppet.StartCustomMXID(false) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
homeserverURL, found := br.Config.Bridge.DoublePuppetServerMap[homeserver] | ||
if !found { | ||
if homeserver == br.AS.HomeserverDomain { | ||
homeserverURL = "" | ||
} else if br.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 | ||
br.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) | ||
} | ||
return err | ||
} | ||
|
||
return br.AS.NewExternalMautrixClient(mxid, accessToken, homeserverURL) | ||
// TODO leave rooms with default puppet | ||
return nil | ||
} | ||
|
||
func (puppet *Puppet) clearCustomMXID() { | ||
func (puppet *Puppet) ClearCustomMXID() { | ||
save := puppet.CustomMXID != "" || puppet.AccessToken != "" | ||
puppet.bridge.puppetsLock.Lock() | ||
if puppet.CustomMXID != "" && puppet.bridge.puppetsByCustomMXID[puppet.CustomMXID] == puppet { | ||
delete(puppet.bridge.puppetsByCustomMXID, puppet.CustomMXID) | ||
} | ||
puppet.bridge.puppetsLock.Unlock() | ||
puppet.CustomMXID = "" | ||
puppet.AccessToken = "" | ||
puppet.customIntent = nil | ||
puppet.customUser = nil | ||
} | ||
|
||
func (puppet *Puppet) newCustomIntent() (*appservice.IntentAPI, error) { | ||
if puppet.CustomMXID == "" { | ||
return nil, ErrNoCustomMXID | ||
} | ||
|
||
client, err := puppet.bridge.newDoublePuppetClient(puppet.CustomMXID, puppet.AccessToken) | ||
if err != nil { | ||
return nil, err | ||
if save { | ||
puppet.Update() | ||
} | ||
|
||
ia := puppet.bridge.AS.NewIntentAPI("custom") | ||
ia.Client = client | ||
ia.Localpart, _, _ = puppet.CustomMXID.Parse() | ||
ia.UserID = puppet.CustomMXID | ||
ia.IsCustomPuppet = true | ||
return ia, nil | ||
} | ||
|
||
func (puppet *Puppet) StartCustomMXID(reloginOnFail bool) error { | ||
if puppet.CustomMXID == "" { | ||
puppet.clearCustomMXID() | ||
return nil | ||
} | ||
|
||
intent, err := puppet.newCustomIntent() | ||
newIntent, newAccessToken, err := puppet.bridge.DoublePuppet.Setup(puppet.CustomMXID, puppet.AccessToken, reloginOnFail) | ||
if err != nil { | ||
puppet.clearCustomMXID() | ||
puppet.ClearCustomMXID() | ||
return err | ||
} | ||
|
||
resp, err := intent.Whoami() | ||
if err != nil { | ||
if !reloginOnFail || (errors.Is(err, mautrix.MUnknownToken) && !puppet.tryRelogin(err, "initializing double puppeting")) { | ||
puppet.clearCustomMXID() | ||
return err | ||
} | ||
|
||
intent.AccessToken = puppet.AccessToken | ||
} else if resp.UserID != puppet.CustomMXID { | ||
puppet.clearCustomMXID() | ||
return ErrMismatchingMXID | ||
puppet.bridge.puppetsLock.Lock() | ||
puppet.bridge.puppetsByCustomMXID[puppet.CustomMXID] = puppet | ||
puppet.bridge.puppetsLock.Unlock() | ||
if puppet.AccessToken != newAccessToken { | ||
puppet.AccessToken = newAccessToken | ||
puppet.Update() | ||
} | ||
|
||
puppet.customIntent = intent | ||
puppet.customIntent = newIntent | ||
puppet.customUser = puppet.bridge.GetUserByMXID(puppet.CustomMXID) | ||
return nil | ||
} | ||
|
||
func (puppet *Puppet) tryRelogin(cause error, action string) bool { | ||
if !puppet.bridge.Config.CanAutoDoublePuppet(puppet.CustomMXID) { | ||
return false | ||
func (user *User) tryAutomaticDoublePuppeting() { | ||
if !user.bridge.Config.CanAutoDoublePuppet(user.MXID) { | ||
return | ||
} | ||
log := puppet.log.With(). | ||
AnErr("cause_error", cause). | ||
Str("while_action", action). | ||
Logger() | ||
log.Debug().Msg("Trying to relogin") | ||
accessToken, err := puppet.loginWithSharedSecret(puppet.CustomMXID) | ||
if err != nil { | ||
log.Error().Err(err).Msg("Failed to relogin") | ||
return false | ||
user.log.Debug().Msg("Checking if double puppeting needs to be enabled") | ||
puppet := user.bridge.GetPuppetByID(user.DiscordID) | ||
if len(puppet.CustomMXID) > 0 { | ||
user.log.Debug().Msg("User already has double-puppeting enabled") | ||
// Custom puppet already enabled | ||
return | ||
} | ||
log.Info().Msg("Successfully relogined") | ||
puppet.AccessToken = accessToken | ||
puppet.Update() | ||
return true | ||
} | ||
|
||
func (puppet *Puppet) loginWithSharedSecret(mxid id.UserID) (string, error) { | ||
_, homeserver, _ := mxid.Parse() | ||
puppet.log.Debug().Str("user_id", mxid.String()).Msg("Logging into double puppet target with shared secret") | ||
loginSecret := puppet.bridge.Config.Bridge.LoginSharedSecretMap[homeserver] | ||
client, err := puppet.bridge.newDoublePuppetClient(mxid, "") | ||
puppet.CustomMXID = user.MXID | ||
err := puppet.StartCustomMXID(true) | ||
if err != nil { | ||
return "", fmt.Errorf("failed to create mautrix client to log in: %v", err) | ||
} | ||
req := mautrix.ReqLogin{ | ||
Identifier: mautrix.UserIdentifier{Type: mautrix.IdentifierTypeUser, User: string(mxid)}, | ||
DeviceID: "Discord Bridge", | ||
InitialDeviceDisplayName: "Discord Bridge", | ||
} | ||
if loginSecret == "appservice" { | ||
client.AccessToken = puppet.bridge.AS.Registration.AppToken | ||
req.Type = mautrix.AuthTypeAppservice | ||
user.log.Warn().Err(err).Msg("Failed to login with shared secret") | ||
} else { | ||
mac := hmac.New(sha512.New, []byte(loginSecret)) | ||
mac.Write([]byte(mxid)) | ||
req.Password = hex.EncodeToString(mac.Sum(nil)) | ||
req.Type = mautrix.AuthTypePassword | ||
} | ||
resp, err := client.Login(&req) | ||
if err != nil { | ||
return "", err | ||
} | ||
return resp.AccessToken, nil | ||
} | ||
|
||
func (puppet *Puppet) SwitchCustomMXID(accessToken string, mxid id.UserID) error { | ||
prevCustomMXID := puppet.CustomMXID | ||
puppet.CustomMXID = mxid | ||
puppet.AccessToken = accessToken | ||
|
||
err := puppet.StartCustomMXID(false) | ||
if err != nil { | ||
return err | ||
// TODO leave rooms with default puppet | ||
user.log.Debug().Msg("Successfully automatically enabled custom puppet") | ||
} | ||
|
||
if prevCustomMXID != "" { | ||
delete(puppet.bridge.puppetsByCustomMXID, prevCustomMXID) | ||
} | ||
if puppet.CustomMXID != "" { | ||
puppet.bridge.puppetsByCustomMXID[puppet.CustomMXID] = puppet | ||
} | ||
puppet.bridge.AS.StateStore.MarkRegistered(puppet.CustomMXID) | ||
puppet.Update() | ||
// TODO leave rooms with default puppet | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters