Add command for Google account login
This commit is contained in:
parent
02f0b9e2ca
commit
20d05c90d3
2 changed files with 112 additions and 17 deletions
73
commands.go
73
commands.go
|
@ -17,6 +17,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -40,7 +41,8 @@ type WrappedCommandEvent struct {
|
||||||
func (br *GMBridge) RegisterCommands() {
|
func (br *GMBridge) RegisterCommands() {
|
||||||
proc := br.CommandProcessor.(*commands.Processor)
|
proc := br.CommandProcessor.(*commands.Processor)
|
||||||
proc.AddHandlers(
|
proc.AddHandlers(
|
||||||
cmdLogin,
|
cmdLoginQR,
|
||||||
|
cmdLoginGoogle,
|
||||||
cmdDeleteSession,
|
cmdDeleteSession,
|
||||||
cmdLogout,
|
cmdLogout,
|
||||||
cmdReconnect,
|
cmdReconnect,
|
||||||
|
@ -70,16 +72,17 @@ var (
|
||||||
HelpSectionPortalManagement = commands.HelpSection{Name: "Portal management", Order: 20}
|
HelpSectionPortalManagement = commands.HelpSection{Name: "Portal management", Order: 20}
|
||||||
)
|
)
|
||||||
|
|
||||||
var cmdLogin = &commands.FullHandler{
|
var cmdLoginQR = &commands.FullHandler{
|
||||||
Func: wrapCommand(fnLogin),
|
Func: wrapCommand(fnLoginQR),
|
||||||
Name: "login",
|
Name: "login-qr",
|
||||||
|
Aliases: []string{"login"},
|
||||||
Help: commands.HelpMeta{
|
Help: commands.HelpMeta{
|
||||||
Section: commands.HelpSectionAuth,
|
Section: commands.HelpSectionAuth,
|
||||||
Description: "Link the bridge to Google Messages on your Android phone as a web client.",
|
Description: "Link the bridge to Google Messages on your Android phone by scanning a QR code.",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnLogin(ce *WrappedCommandEvent) {
|
func fnLoginQR(ce *WrappedCommandEvent) {
|
||||||
if ce.User.Session != nil {
|
if ce.User.Session != nil {
|
||||||
if ce.User.IsConnected() {
|
if ce.User.IsConnected() {
|
||||||
ce.Reply("You're already logged in")
|
ce.Reply("You're already logged in")
|
||||||
|
@ -123,6 +126,64 @@ func fnLogin(ce *WrappedCommandEvent) {
|
||||||
ce.ZLog.Trace().Msg("Login command finished")
|
ce.ZLog.Trace().Msg("Login command finished")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var cmdLoginGoogle = &commands.FullHandler{
|
||||||
|
Func: wrapCommand(fnLoginGoogle),
|
||||||
|
Name: "login-google",
|
||||||
|
Aliases: []string{"login"},
|
||||||
|
Help: commands.HelpMeta{
|
||||||
|
Section: commands.HelpSectionAuth,
|
||||||
|
Description: "Link the bridge to Google Messages on your Android phone by logging in with your Google account.",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func fnLoginGoogle(ce *WrappedCommandEvent) {
|
||||||
|
if ce.User.Session != nil {
|
||||||
|
if ce.User.IsConnected() {
|
||||||
|
ce.Reply("You're already logged in")
|
||||||
|
} else {
|
||||||
|
ce.Reply("You're already logged in. Perhaps you wanted to `reconnect`?")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
} else if ce.User.pairSuccessChan != nil {
|
||||||
|
ce.Reply("You already have a login in progress")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ce.User.CommandState = &commands.CommandState{
|
||||||
|
Next: commands.MinimalHandlerFunc(wrapCommand(fnLoginGoogleCookies)),
|
||||||
|
Action: "Login",
|
||||||
|
}
|
||||||
|
ce.Reply("Send your Google cookies here, formatted as a key-value JSON object (see <https://docs.mau.fi/bridges/go/gmessages/authentication.html> for details)")
|
||||||
|
}
|
||||||
|
|
||||||
|
func fnLoginGoogleCookies(ce *WrappedCommandEvent) {
|
||||||
|
ce.User.CommandState = nil
|
||||||
|
if ce.User.Session != nil {
|
||||||
|
if ce.User.IsConnected() {
|
||||||
|
ce.Reply("You're already logged in")
|
||||||
|
} else {
|
||||||
|
ce.Reply("You're already logged in. Perhaps you wanted to `reconnect`?")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
} else if ce.User.pairSuccessChan != nil {
|
||||||
|
ce.Reply("You already have a login in progress")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var cookies map[string]string
|
||||||
|
err := json.Unmarshal([]byte(ce.RawArgs), &cookies)
|
||||||
|
if err != nil {
|
||||||
|
ce.Reply("Failed to parse cookies: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = ce.User.LoginGoogle(cookies, func(emoji string) {
|
||||||
|
ce.Reply(emoji)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ce.Reply("Login failed: %v", err)
|
||||||
|
} else {
|
||||||
|
ce.Reply("Login successful")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (user *User) sendQREdit(ce *WrappedCommandEvent, content *event.MessageEventContent, prevEvent id.EventID) id.EventID {
|
func (user *User) sendQREdit(ce *WrappedCommandEvent, content *event.MessageEventContent, prevEvent id.EventID) id.EventID {
|
||||||
if len(prevEvent) != 0 {
|
if len(prevEvent) != 0 {
|
||||||
content.SetEdit(prevEvent)
|
content.SetEdit(prevEvent)
|
||||||
|
|
44
user.go
44
user.go
|
@ -35,6 +35,7 @@ import (
|
||||||
"maunium.net/go/mautrix/appservice"
|
"maunium.net/go/mautrix/appservice"
|
||||||
"maunium.net/go/mautrix/bridge"
|
"maunium.net/go/mautrix/bridge"
|
||||||
"maunium.net/go/mautrix/bridge/bridgeconfig"
|
"maunium.net/go/mautrix/bridge/bridgeconfig"
|
||||||
|
"maunium.net/go/mautrix/bridge/commands"
|
||||||
"maunium.net/go/mautrix/bridge/status"
|
"maunium.net/go/mautrix/bridge/status"
|
||||||
"maunium.net/go/mautrix/event"
|
"maunium.net/go/mautrix/event"
|
||||||
"maunium.net/go/mautrix/format"
|
"maunium.net/go/mautrix/format"
|
||||||
|
@ -65,6 +66,7 @@ type User struct {
|
||||||
connLock sync.Mutex
|
connLock sync.Mutex
|
||||||
|
|
||||||
BridgeState *bridge.BridgeStateQueue
|
BridgeState *bridge.BridgeStateQueue
|
||||||
|
CommandState *commands.CommandState
|
||||||
|
|
||||||
spaceMembershipChecked bool
|
spaceMembershipChecked bool
|
||||||
|
|
||||||
|
@ -83,13 +85,22 @@ type User struct {
|
||||||
loginInProgress atomic.Bool
|
loginInProgress atomic.Bool
|
||||||
pairSuccessChan chan struct{}
|
pairSuccessChan chan struct{}
|
||||||
ongoingLoginChan <-chan qrChannelItem
|
ongoingLoginChan <-chan qrChannelItem
|
||||||
loginChanReadLock sync.Mutex
|
|
||||||
lastQRCode string
|
lastQRCode string
|
||||||
cancelLogin func()
|
cancelLogin func()
|
||||||
|
|
||||||
DoublePuppetIntent *appservice.IntentAPI
|
DoublePuppetIntent *appservice.IntentAPI
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (user *User) GetCommandState() *commands.CommandState {
|
||||||
|
return user.CommandState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (user *User) SetCommandState(state *commands.CommandState) {
|
||||||
|
user.CommandState = state
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ commands.CommandingUser = (*User)(nil)
|
||||||
|
|
||||||
func (br *GMBridge) getUserByMXID(userID id.UserID, onlyIfExists bool) *User {
|
func (br *GMBridge) getUserByMXID(userID id.UserID, onlyIfExists bool) *User {
|
||||||
_, isPuppet := br.ParsePuppetMXID(userID)
|
_, isPuppet := br.ParsePuppetMXID(userID)
|
||||||
if isPuppet || userID == br.Bot.UserID {
|
if isPuppet || userID == br.Bot.UserID {
|
||||||
|
@ -155,10 +166,6 @@ func (user *User) GetMXID() id.UserID {
|
||||||
return user.MXID
|
return user.MXID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (user *User) GetCommandState() map[string]interface{} {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (br *GMBridge) GetUserByMXIDIfExists(userID id.UserID) *User {
|
func (br *GMBridge) GetUserByMXIDIfExists(userID id.UserID) *User {
|
||||||
return br.getUserByMXID(userID, true)
|
return br.getUserByMXID(userID, true)
|
||||||
}
|
}
|
||||||
|
@ -456,6 +463,33 @@ func (user *User) Login(maxAttempts int) (<-chan qrChannelItem, error) {
|
||||||
return ch, nil
|
return ch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (user *User) LoginGoogle(cookies map[string]string, emojiCallback func(string)) error {
|
||||||
|
user.connLock.Lock()
|
||||||
|
defer user.connLock.Unlock()
|
||||||
|
if user.Session != nil {
|
||||||
|
return ErrAlreadyLoggedIn
|
||||||
|
} else if !user.loginInProgress.CompareAndSwap(false, true) {
|
||||||
|
return ErrLoginInProgress
|
||||||
|
}
|
||||||
|
if user.Client != nil {
|
||||||
|
user.unlockedDeleteConnection()
|
||||||
|
}
|
||||||
|
pairSuccessChan := make(chan struct{})
|
||||||
|
user.pairSuccessChan = pairSuccessChan
|
||||||
|
authData := libgm.NewAuthData()
|
||||||
|
authData.Cookies = cookies
|
||||||
|
user.createClient(authData)
|
||||||
|
Analytics.Track(user.MXID, "$login_start")
|
||||||
|
err := user.Client.DoGaiaPairing(emojiCallback)
|
||||||
|
if err != nil {
|
||||||
|
user.unlockedDeleteConnection()
|
||||||
|
user.pairSuccessChan = nil
|
||||||
|
user.loginInProgress.Store(false)
|
||||||
|
return fmt.Errorf("failed to connect to Google Messages: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (user *User) Connect() bool {
|
func (user *User) Connect() bool {
|
||||||
user.connLock.Lock()
|
user.connLock.Lock()
|
||||||
defer user.connLock.Unlock()
|
defer user.connLock.Unlock()
|
||||||
|
|
Loading…
Reference in a new issue