2023-07-02 14:21:55 +00:00
|
|
|
// mautrix-gmessages - A Matrix-Google Messages puppeting bridge.
|
|
|
|
// Copyright (C) 2023 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 <https://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
_ "embed"
|
2023-10-09 12:03:58 +00:00
|
|
|
"net/url"
|
2023-07-02 14:21:55 +00:00
|
|
|
"sync"
|
|
|
|
|
2023-08-08 13:13:44 +00:00
|
|
|
"go.mau.fi/util/configupgrade"
|
2023-07-02 14:21:55 +00:00
|
|
|
"maunium.net/go/mautrix/bridge"
|
|
|
|
"maunium.net/go/mautrix/bridge/commands"
|
|
|
|
"maunium.net/go/mautrix/bridge/status"
|
|
|
|
"maunium.net/go/mautrix/id"
|
|
|
|
|
|
|
|
"go.mau.fi/mautrix-gmessages/config"
|
|
|
|
"go.mau.fi/mautrix-gmessages/database"
|
2023-07-17 13:51:31 +00:00
|
|
|
"go.mau.fi/mautrix-gmessages/libgm/gmproto"
|
2023-07-16 12:55:30 +00:00
|
|
|
"go.mau.fi/mautrix-gmessages/libgm/util"
|
2023-07-02 14:21:55 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Information to find out exactly which commit the bridge was built from.
|
|
|
|
// These are filled at build time with the -X linker flag.
|
|
|
|
var (
|
|
|
|
Tag = "unknown"
|
|
|
|
Commit = "unknown"
|
|
|
|
BuildTime = "unknown"
|
|
|
|
)
|
|
|
|
|
|
|
|
//go:embed example-config.yaml
|
|
|
|
var ExampleConfig string
|
|
|
|
|
|
|
|
type GMBridge struct {
|
|
|
|
bridge.Bridge
|
2023-07-16 22:13:46 +00:00
|
|
|
Config *config.Config
|
|
|
|
DB *database.Database
|
|
|
|
Provisioning *ProvisioningAPI
|
2023-07-02 14:21:55 +00:00
|
|
|
|
|
|
|
usersByMXID map[id.UserID]*User
|
|
|
|
usersLock sync.Mutex
|
|
|
|
spaceRooms map[id.RoomID]*User
|
|
|
|
spaceRoomsLock sync.Mutex
|
|
|
|
managementRooms map[id.RoomID]*User
|
|
|
|
managementRoomsLock sync.Mutex
|
|
|
|
portalsByMXID map[id.RoomID]*Portal
|
|
|
|
portalsByKey map[database.Key]*Portal
|
2023-09-04 22:34:47 +00:00
|
|
|
portalsByOtherUser map[database.Key]*Portal
|
2023-07-02 14:21:55 +00:00
|
|
|
portalsLock sync.Mutex
|
|
|
|
puppetsByKey map[database.Key]*Puppet
|
|
|
|
puppetsLock sync.Mutex
|
|
|
|
}
|
|
|
|
|
|
|
|
func (br *GMBridge) Init() {
|
|
|
|
br.CommandProcessor = commands.NewProcessor(&br.Bridge)
|
|
|
|
br.RegisterCommands()
|
|
|
|
|
2023-07-16 13:19:33 +00:00
|
|
|
util.BrowserDetailsMessage.OS = br.Config.GoogleMessages.OS
|
2023-07-17 23:57:20 +00:00
|
|
|
browserVal, ok := gmproto.BrowserType_value[br.Config.GoogleMessages.Browser]
|
2023-07-15 23:49:14 +00:00
|
|
|
if !ok {
|
|
|
|
br.ZLog.Error().Str("browser_value", br.Config.GoogleMessages.Browser).Msg("Invalid browser value")
|
|
|
|
} else {
|
2023-07-17 23:57:20 +00:00
|
|
|
util.BrowserDetailsMessage.BrowserType = gmproto.BrowserType(browserVal)
|
2023-07-15 23:49:14 +00:00
|
|
|
}
|
2023-08-24 08:16:08 +00:00
|
|
|
deviceVal, ok := gmproto.DeviceType_value[br.Config.GoogleMessages.Device]
|
|
|
|
if !ok {
|
|
|
|
br.ZLog.Error().Str("device_value", br.Config.GoogleMessages.Device).Msg("Invalid device value")
|
|
|
|
} else {
|
|
|
|
util.BrowserDetailsMessage.DeviceType = gmproto.DeviceType(deviceVal)
|
|
|
|
}
|
2023-07-15 23:49:14 +00:00
|
|
|
|
2023-10-09 12:03:58 +00:00
|
|
|
Analytics.log = br.ZLog.With().Str("component", "segment").Logger()
|
|
|
|
Analytics.url = (&url.URL{
|
|
|
|
Scheme: "https",
|
|
|
|
Host: br.Config.Analytics.Host,
|
|
|
|
Path: "/v1/track",
|
|
|
|
}).String()
|
|
|
|
Analytics.key = br.Config.Analytics.Token
|
|
|
|
Analytics.userID = br.Config.Analytics.UserID
|
|
|
|
if Analytics.IsEnabled() {
|
|
|
|
Analytics.log.Info().Msg("Analytics are enabled")
|
|
|
|
if Analytics.userID != "" {
|
|
|
|
Analytics.log.Info().Str("user_id", Analytics.userID).Msg("Overriding Analytics user ID")
|
2023-07-02 14:21:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
br.DB = database.New(br.Bridge.DB)
|
|
|
|
|
|
|
|
ss := br.Config.Bridge.Provisioning.SharedSecret
|
|
|
|
if len(ss) > 0 && ss != "disable" {
|
2023-07-16 22:13:46 +00:00
|
|
|
br.Provisioning = &ProvisioningAPI{bridge: br}
|
2023-07-02 14:21:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (br *GMBridge) Start() {
|
2023-07-16 22:13:46 +00:00
|
|
|
if br.Provisioning != nil {
|
|
|
|
br.ZLog.Debug().Msg("Initializing provisioning API")
|
|
|
|
br.Provisioning.Init()
|
|
|
|
}
|
2023-07-02 14:21:55 +00:00
|
|
|
br.WaitWebsocketConnected()
|
|
|
|
go br.StartUsers()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (br *GMBridge) StartUsers() {
|
|
|
|
br.ZLog.Debug().Msg("Starting users")
|
|
|
|
foundAnySessions := false
|
|
|
|
for _, user := range br.GetAllUsersWithSession() {
|
|
|
|
foundAnySessions = true
|
|
|
|
go user.Connect()
|
|
|
|
}
|
|
|
|
if !foundAnySessions {
|
|
|
|
br.SendGlobalBridgeState(status.BridgeState{StateEvent: status.StateUnconfigured}.Fill(nil))
|
|
|
|
}
|
|
|
|
br.ZLog.Debug().Msg("Starting custom puppets")
|
|
|
|
for _, loopuser := range br.GetAllUsersWithDoublePuppet() {
|
|
|
|
go func(user *User) {
|
|
|
|
user.zlog.Debug().Msg("Starting double puppet")
|
2023-08-21 10:52:03 +00:00
|
|
|
err := user.StartCustomMXID(true)
|
2023-07-02 14:21:55 +00:00
|
|
|
if err != nil {
|
|
|
|
user.zlog.Err(err).Msg("Failed to start double puppet")
|
|
|
|
}
|
|
|
|
}(loopuser)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (br *GMBridge) Stop() {
|
2023-08-10 12:55:33 +00:00
|
|
|
for _, user := range br.usersByMXID {
|
2023-07-02 14:21:55 +00:00
|
|
|
if user.Client == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
br.ZLog.Debug().Str("user_id", user.MXID.String()).Msg("Disconnecting user")
|
|
|
|
user.Client.Disconnect()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (br *GMBridge) GetExampleConfig() string {
|
|
|
|
return ExampleConfig
|
|
|
|
}
|
|
|
|
|
|
|
|
func (br *GMBridge) GetConfigPtr() interface{} {
|
|
|
|
br.Config = &config.Config{
|
|
|
|
BaseConfig: &br.Bridge.Config,
|
|
|
|
}
|
|
|
|
br.Config.BaseConfig.Bridge = &br.Config.Bridge
|
|
|
|
return br.Config
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
br := &GMBridge{
|
2023-09-04 22:34:47 +00:00
|
|
|
usersByMXID: make(map[id.UserID]*User),
|
|
|
|
spaceRooms: make(map[id.RoomID]*User),
|
|
|
|
managementRooms: make(map[id.RoomID]*User),
|
|
|
|
portalsByMXID: make(map[id.RoomID]*Portal),
|
|
|
|
portalsByKey: make(map[database.Key]*Portal),
|
|
|
|
portalsByOtherUser: make(map[database.Key]*Portal),
|
|
|
|
puppetsByKey: make(map[database.Key]*Puppet),
|
2023-07-02 14:21:55 +00:00
|
|
|
}
|
|
|
|
br.Bridge = bridge.Bridge{
|
|
|
|
Name: "mautrix-gmessages",
|
|
|
|
URL: "https://github.com/mautrix/gmessages",
|
|
|
|
Description: "A Matrix-Google Messages puppeting bridge.",
|
2023-09-16 14:39:51 +00:00
|
|
|
Version: "0.2.0",
|
2023-07-02 14:21:55 +00:00
|
|
|
ProtocolName: "Google Messages",
|
2023-09-04 22:34:47 +00:00
|
|
|
BeeperServiceName: "gmessages",
|
|
|
|
BeeperNetworkName: "gmessages",
|
2023-07-02 14:21:55 +00:00
|
|
|
|
|
|
|
CryptoPickleKey: "go.mau.fi/mautrix-gmessages",
|
|
|
|
|
|
|
|
ConfigUpgrader: &configupgrade.StructUpgrader{
|
|
|
|
SimpleUpgrader: configupgrade.SimpleUpgrader(config.DoUpgrade),
|
|
|
|
Blocks: config.SpacedBlocks,
|
|
|
|
Base: ExampleConfig,
|
|
|
|
},
|
|
|
|
|
|
|
|
Child: br,
|
|
|
|
}
|
|
|
|
br.InitVersion(Tag, Commit, BuildTime)
|
|
|
|
|
|
|
|
br.Main()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (br *GMBridge) CreatePrivatePortal(roomID id.RoomID, brUser bridge.User, brGhost bridge.Ghost) {
|
|
|
|
//TODO implement?
|
|
|
|
}
|