Skip to content

Commit

Permalink
init pkg/connector
Browse files Browse the repository at this point in the history
  • Loading branch information
rnons committed Nov 28, 2024
1 parent c55390b commit 6ca3320
Show file tree
Hide file tree
Showing 6 changed files with 293 additions and 1 deletion.
4 changes: 3 additions & 1 deletion cmd/mautrix-googlechat/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
package main

import (
"go.mau.fi/mautrix-googlechat/pkg/connector"

"maunium.net/go/mautrix/bridgev2/matrix/mxmain"
)

Expand All @@ -31,7 +33,7 @@ var m = mxmain.BridgeMain{
Description: "A Matrix-Google Chat puppeting bridge",
URL: "https://github.com/mautrix/googlechat",
Version: "0.6.0",
//Connector: c,
Connector: &connector.GchatConnector{},
}

func main() {
Expand Down
93 changes: 93 additions & 0 deletions pkg/connector/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package connector

import (
"context"

"go.mau.fi/mautrix-googlechat/pkg/gchatmeow"

"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/bridgev2/networkid"
"maunium.net/go/mautrix/bridgev2/simplevent"
)

type GchatClient struct {
UserLogin *bridgev2.UserLogin
Client *gchatmeow.Client
}

var (
_ bridgev2.NetworkAPI = (*GchatClient)(nil)
)

func (c *GchatClient) Connect(ctx context.Context) error {
_, err := c.Client.LoadMessagesPage()
if err != nil {
return err
}
err = c.Client.Connect()
if err != nil {
return err
}
return c.onConnect(ctx)
}

func (c *GchatClient) Disconnect() {
}

func (c *GchatClient) GetCapabilities(ctx context.Context, portal *bridgev2.Portal) *bridgev2.NetworkRoomCapabilities {
return nil
}

func (c *GchatClient) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) (*bridgev2.ChatInfo, error) {
return nil, nil
}

func (c *GchatClient) GetUserInfo(ctx context.Context, ghost *bridgev2.Ghost) (*bridgev2.UserInfo, error) {
return nil, nil
}

func (c *GchatClient) IsLoggedIn() bool {
return false
}

func (c *GchatClient) IsThisUser(ctx context.Context, userID networkid.UserID) bool {
return networkid.UserID(c.UserLogin.ID) == userID
}

func (c *GchatClient) LogoutRemote(ctx context.Context) {
}

func (c *GchatClient) onConnect(ctx context.Context) error {
res, err := c.Client.GetPaginatedWorlds(nil)
if err != nil {
return err
}
for _, item := range res.WorldItems {
// TODO room name for DM, and full members list
name := item.GetRoomName()
memberMap := map[networkid.UserID]bridgev2.ChatMember{}
memberMap[networkid.UserID(c.UserLogin.ID)] = bridgev2.ChatMember{
EventSender: bridgev2.EventSender{
IsFromMe: true,
Sender: networkid.UserID(c.UserLogin.ID),
},
}
c.UserLogin.Bridge.QueueRemoteEvent(c.UserLogin, &simplevent.ChatResync{
EventMeta: simplevent.EventMeta{
Type: bridgev2.RemoteEventChatResync,
PortalKey: networkid.PortalKey{
ID: networkid.PortalID(item.GroupId.String()),
Receiver: c.UserLogin.ID,
},
CreatePortal: true,
},
ChatInfo: &bridgev2.ChatInfo{
Name: &name,
Members: &bridgev2.ChatMemberList{
MemberMap: memberMap,
},
},
})
}
return nil
}
55 changes: 55 additions & 0 deletions pkg/connector/connector.go
Original file line number Diff line number Diff line change
@@ -1 +1,56 @@
package connector

import (
"context"

"go.mau.fi/util/configupgrade"
"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/bridgev2/database"
)

type GchatConnector struct {
Bridge *bridgev2.Bridge
}

var (
_ bridgev2.NetworkConnector = (*GchatConnector)(nil)
)

func (gc *GchatConnector) Init(bridge *bridgev2.Bridge) {
gc.Bridge = bridge
}

func (gc *GchatConnector) Start(ctx context.Context) error {
return nil
}

func (gc *GchatConnector) GetName() bridgev2.BridgeName {
return bridgev2.BridgeName{
DisplayName: "Google Chat",
NetworkURL: "https://chat.google.com",
NetworkIcon: "mxc://maunium.net/BDIWAQcbpPGASPUUBuEGWXnQ",
NetworkID: "googlechat",
BeeperBridgeType: "go.mau.fi/googlechat",
DefaultPort: 29320,
}
}

func (gc *GchatConnector) GetCapabilities() *bridgev2.NetworkGeneralCapabilities {
return &bridgev2.NetworkGeneralCapabilities{}
}

func (gc *GchatConnector) GetConfig() (example string, data any, upgrader configupgrade.Upgrader) {
return "", nil, nil
}

func (gc *GchatConnector) GetDBMetaTypes() database.MetaTypes {
return database.MetaTypes{
Portal: nil,
Ghost: nil,
Message: nil,
Reaction: nil,
UserLogin: func() any {
return &UserLoginMetadata{}
},
}
}
11 changes: 11 additions & 0 deletions pkg/connector/handlematrix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package connector

import (
"context"

"maunium.net/go/mautrix/bridgev2"
)

func (c *GchatClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.MatrixMessage) (message *bridgev2.MatrixMessageResponse, err error) {
return nil, nil
}
122 changes: 122 additions & 0 deletions pkg/connector/login.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package connector

import (
"context"
"fmt"

"go.mau.fi/mautrix-googlechat/pkg/gchatmeow"
"go.mau.fi/mautrix-googlechat/pkg/gchatmeow/cookies"
"go.mau.fi/mautrix-googlechat/pkg/gchatmeow/debug"

"maunium.net/go/mautrix/bridge/status"
"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/bridgev2/database"
"maunium.net/go/mautrix/bridgev2/networkid"
"maunium.net/go/mautrix/id"
)

const (
LoginStepIDCookies = "com.beeper.googlechat.login.cookies"
LoginStepIDComplete = "com.beeper.googlechat.login.complete"
)

func (gc *GchatConnector) CreateLogin(ctx context.Context, user *bridgev2.User, flowID string) (bridgev2.LoginProcess, error) {
return &GchatCookieLogin{User: user}, nil
}

func (gc *GchatConnector) GetLoginFlows() []bridgev2.LoginFlow {
return []bridgev2.LoginFlow{{
Name: "Cookies",
Description: "Log in with your cookies",
ID: "cookies",
}}
}

func (gc *GchatConnector) LoadUserLogin(ctx context.Context, login *bridgev2.UserLogin) error {
loginMetadata := login.Metadata.(*UserLoginMetadata)
var client *gchatmeow.Client
clientOptions := gchatmeow.ClientOpts{
Cookies: cookies.NewCookiesFromString(loginMetadata.Cookies),
}
client = gchatmeow.NewClient(&clientOptions, debug.NewLogger())
c := &GchatClient{
UserLogin: login,
Client: client,
}
login.Client = c
return nil
}

type GchatCookieLogin struct {
User *bridgev2.User
}

type UserLoginMetadata struct {
Cookies string
}

var _ bridgev2.LoginProcessCookies = (*GchatCookieLogin)(nil)

func (gl *GchatCookieLogin) Start(ctx context.Context) (*bridgev2.LoginStep, error) {
step := &bridgev2.LoginStep{
Type: bridgev2.LoginStepTypeCookies,
StepID: LoginStepIDCookies,
Instructions: "Enter a JSON object with your cookies, or a cURL command copied from browser devtools.",
CookiesParams: &bridgev2.LoginCookiesParams{
URL: "https://chat.google.com/",
},
}
return step, nil
}

func (gl *GchatCookieLogin) Cancel() {}

func (gl *GchatCookieLogin) SubmitCookies(ctx context.Context, strCookies map[string]string) (*bridgev2.LoginStep, error) {
cookies := &cookies.Cookies{}
cookies.UpdateValues(strCookies)

clientOptions := gchatmeow.ClientOpts{
Cookies: cookies,
}
client := gchatmeow.NewClient(&clientOptions, debug.NewLogger())

initialData, err := client.LoadMessagesPage()
if err != nil {
return nil, err
}

user := initialData.CurrentUser.Data

userId := user.Id.Id
ul, err := gl.User.NewLogin(ctx, &database.UserLogin{
ID: networkid.UserLoginID(userId),
RemoteName: user.Fullname,
RemoteProfile: status.RemoteProfile{
Name: user.Fullname,
Email: user.Email,
Avatar: id.ContentURIString(user.GetAvatarUrl()),
},
Metadata: &UserLoginMetadata{
Cookies: cookies.String(),
},
}, nil)

if err != nil {
return nil, fmt.Errorf("failed to save new login: %w", err)
}

ul.Client.Connect(ctx)
c := ul.Client.(*GchatClient)
c.UserLogin = ul
c.Client = client

return &bridgev2.LoginStep{
Type: bridgev2.LoginStepTypeComplete,
StepID: LoginStepIDComplete,
Instructions: fmt.Sprintf("Logged in as %s (%s)", user.Fullname, userId),
CompleteParams: &bridgev2.LoginCompleteParams{
UserLoginID: ul.ID,
UserLogin: ul,
},
}, nil
}
9 changes: 9 additions & 0 deletions pkg/gchatmeow/cookies/cookies.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@ func NewCookies() *Cookies {
}
}

func (c *Cookies) UpdateValues(newValues map[string]string) {
c.lock.Lock()
defer c.lock.Unlock()
c.store = make(map[GChatCookieName]string)
for k, v := range newValues {
c.store[GChatCookieName(k)] = v
}
}

func NewCookiesFromString(cookieStr string) *Cookies {
c := NewCookies()
cookieStrings := strings.Split(cookieStr, ";")
Expand Down

0 comments on commit 6ca3320

Please sign in to comment.