Refactor more things

This commit is contained in:
Tulir Asokan 2023-07-16 14:36:13 +03:00
parent e6cec49353
commit 3fefda3a96
19 changed files with 138 additions and 256 deletions

View file

@ -15,7 +15,6 @@ import (
"go.mau.fi/mautrix-gmessages/libgm"
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/crypto"
"go.mau.fi/mautrix-gmessages/libgm/events"
)
@ -44,14 +43,12 @@ func main() {
if !errors.Is(err, os.ErrNotExist) {
panic(err)
}
sess = *libgm.NewAuthData()
} else {
must(json.NewDecoder(file).Decode(&sess))
log.Info().Msg("Loaded session?")
}
_ = file.Close()
if sess.Cryptor == nil {
sess.Cryptor = crypto.NewCryptor(nil, nil)
}
cli = libgm.NewClient(&sess, log)
cli.SetEventHandler(evtHandler)
must(cli.Connect())

View file

@ -11,6 +11,7 @@ import (
"net/http"
"net/url"
"os"
"strconv"
"time"
"github.com/google/uuid"
@ -26,16 +27,25 @@ import (
)
type AuthData struct {
TachyonAuthToken []byte `json:"tachyon_token,omitempty"`
TTL int64 `json:"ttl,omitempty"`
AuthenticatedAt *time.Time `json:"authenticated_at,omitempty"`
// Keys used to encrypt communication with the phone
RequestCrypto *crypto.AESCTRHelper `json:"request_crypto,omitempty"`
// Key used to sign requests to refresh the tachyon auth token from the server
RefreshKey *crypto.JWK `json:"refresh_key,omitempty"`
// Identity of the paired phone and browser
DevicePair *pblite.DevicePair `json:"device_pair,omitempty"`
Cryptor *crypto.Cryptor `json:"crypto,omitempty"`
// Key used to authenticate with the server
TachyonAuthToken []byte `json:"tachyon_token,omitempty"`
TachyonExpiry time.Time `json:"tachyon_expiry,omitempty"`
TachyonTTL int64 `json:"tachyon_ttl,omitempty"`
// Unknown encryption key, not used for anything
WebEncryptionKey []byte `json:"web_encryption_key,omitempty"`
JWK *crypto.JWK `json:"jwk,omitempty"`
}
const RefreshTachyonBuffer = 1 * time.Hour
type Proxy func(*http.Request) (*url.URL, error)
type EventHandler func(evt any)
type Client struct {
Logger zerolog.Logger
rpc *RPC
@ -49,17 +59,18 @@ type Client struct {
http *http.Client
}
func NewAuthData() *AuthData {
return &AuthData{
RequestCrypto: crypto.NewAESCTRHelper(),
RefreshKey: crypto.GenerateECDSAKey(),
}
}
func NewClient(authData *AuthData, logger zerolog.Logger) *Client {
sessionHandler := &SessionHandler{
responseWaiters: make(map[string]chan<- *pblite.Response),
responseTimeout: time.Duration(5000) * time.Millisecond,
}
if authData == nil {
authData = &AuthData{}
}
if authData.Cryptor == nil {
authData.Cryptor = crypto.NewCryptor(nil, nil)
}
cli := &Client{
authData: authData,
Logger: logger,
@ -90,19 +101,12 @@ func (c *Client) SetProxy(proxy string) error {
c.Logger.Debug().Any("proxy", proxyParsed.Host).Msg("SetProxy")
return nil
}
func (c *Client) Connect() error {
if c.authData.TachyonAuthToken != nil {
hasExpired, authenticatedAtSeconds := c.hasTachyonTokenExpired()
if hasExpired {
c.Logger.Error().Any("expired", hasExpired).Any("secondsSince", authenticatedAtSeconds).Msg("TachyonToken has expired! attempting to refresh")
refreshErr := c.refreshAuthToken()
if refreshErr != nil {
panic(refreshErr)
}
}
c.Logger.Info().Any("secondsSince", authenticatedAtSeconds).Any("token", c.authData.TachyonAuthToken).Msg("TachyonToken has not expired, attempting to connect...")
webEncryptionKeyResponse, webEncryptionKeyErr := c.GetWebEncryptionKey()
if webEncryptionKeyErr != nil {
@ -110,13 +114,7 @@ func (c *Client) Connect() error {
return webEncryptionKeyErr
}
c.updateWebEncryptionKey(webEncryptionKeyResponse.GetKey())
rpcPayload, receiveMessageSessionId, err := payload.ReceiveMessages(c.authData.TachyonAuthToken)
if err != nil {
panic(err)
return err
}
c.rpc.rpcSessionId = receiveMessageSessionId
go c.rpc.ListenReceiveMessages(rpcPayload)
go c.rpc.ListenReceiveMessages()
c.sessionHandler.startAckInterval()
bugleRes, bugleErr := c.IsBugleDefault()
@ -128,10 +126,9 @@ func (c *Client) Connect() error {
if sessionErr != nil {
panic(sessionErr)
}
//c.Logger.Debug().Any("tachyonAuthToken", c.authData.TachyonAuthToken).Msg("Successfully connected to server")
return nil
} else {
pairer, err := c.NewPairer(nil, 20)
pairer, err := c.NewPairer(c.authData.RefreshKey, 20)
if err != nil {
panic(err)
}
@ -141,13 +138,7 @@ func (c *Client) Connect() error {
return err2
}
c.authData.TachyonAuthToken = registered.AuthKeyData.TachyonAuthToken
rpcPayload, receiveMessageSessionId, err := payload.ReceiveMessages(c.authData.TachyonAuthToken)
if err != nil {
panic(err)
return err
}
c.rpc.rpcSessionId = receiveMessageSessionId
go c.rpc.ListenReceiveMessages(rpcPayload)
go c.rpc.ListenReceiveMessages()
return nil
}
}
@ -165,19 +156,6 @@ func (c *Client) IsLoggedIn() bool {
return c.authData != nil && c.authData.DevicePair != nil
}
func (c *Client) hasTachyonTokenExpired() (bool, string) {
if c.authData.TachyonAuthToken == nil || c.authData.AuthenticatedAt == nil {
return true, ""
} else {
duration := time.Since(*c.authData.AuthenticatedAt)
seconds := fmt.Sprintf("%.3f", duration.Seconds())
if duration.Microseconds() > 86400000000 {
return true, seconds
}
return false, seconds
}
}
func (c *Client) Reconnect() error {
c.rpc.CloseConnection()
for c.rpc.conn != nil {
@ -281,21 +259,15 @@ func (c *Client) updateWebEncryptionKey(key []byte) {
c.authData.WebEncryptionKey = key
}
func (c *Client) updateJWK(jwk *crypto.JWK) {
c.Logger.Debug().Any("jwk", jwk).Msg("Updated JWK")
c.authData.JWK = jwk
}
func (c *Client) updateTachyonAuthToken(t []byte) {
authenticatedAt := time.Now().UTC()
func (c *Client) updateTachyonAuthToken(t []byte, validFor int64) {
c.authData.TachyonAuthToken = t
c.authData.AuthenticatedAt = &authenticatedAt
c.Logger.Debug().Any("authenticatedAt", authenticatedAt).Any("tachyonAuthToken", t).Msg("Updated TachyonAuthToken")
validForDuration := time.Duration(validFor) * time.Microsecond
if validForDuration == 0 {
validForDuration = 24 * time.Hour
}
func (c *Client) updateTTL(ttl int64) {
c.authData.TTL = ttl
c.Logger.Debug().Any("ttl", ttl).Msg("Updated TTL")
c.authData.TachyonExpiry = time.Now().UTC().Add(time.Microsecond * time.Duration(validFor))
c.authData.TachyonTTL = validForDuration.Microseconds()
c.Logger.Debug().Time("tachyon_expiry", c.authData.TachyonExpiry).Int64("valid_for", validFor).Msg("Updated tachyon token")
}
func (c *Client) updateDevicePair(devicePair *pblite.DevicePair) {
@ -327,12 +299,12 @@ func LoadAuthSession(path string) (*AuthData, error) {
return sessionData, nil
}
func (c *Client) RefreshAuthToken() error {
return c.refreshAuthToken()
}
func (c *Client) refreshAuthToken() error {
jwk := c.authData.JWK
if c.authData.DevicePair == nil || time.Until(c.authData.TachyonExpiry) > RefreshTachyonBuffer {
return nil
}
c.Logger.Debug().Time("tachyon_expiry", c.authData.TachyonExpiry).Msg("Refreshing auth token")
jwk := c.authData.RefreshKey
requestID := uuid.NewString()
timestamp := time.Now().UnixMilli() * 1000
@ -342,14 +314,23 @@ func (c *Client) refreshAuthToken() error {
return err
}
payloadMessage, messageErr := payload.RegisterRefresh(sig, requestID, int64(timestamp), c.authData.DevicePair.Browser, c.authData.TachyonAuthToken)
if messageErr != nil {
return messageErr
payload, err := pblite.Marshal(&binary.RegisterRefreshPayload{
MessageAuth: &binary.AuthMessage{
RequestID: requestID,
TachyonAuthToken: c.authData.TachyonAuthToken,
ConfigVersion: payload.ConfigMessage,
},
CurrBrowserDevice: c.authData.DevicePair.Browser,
UnixTimestamp: timestamp,
Signature: sig,
EmptyRefreshArr: &binary.EmptyRefreshArr{EmptyArr: &binary.EmptyArr{}},
MessageType: 2, // hmm
})
if err != nil {
return err
}
c.Logger.Info().Any("payload", string(payloadMessage)).Msg("Attempting to refresh auth token")
refreshResponse, requestErr := c.rpc.sendMessageRequest(util.RegisterRefreshURL, payloadMessage)
refreshResponse, requestErr := c.rpc.sendMessageRequest(util.RegisterRefreshURL, payload)
if requestErr != nil {
return requestErr
}
@ -377,7 +358,9 @@ func (c *Client) refreshAuthToken() error {
return fmt.Errorf("failed to refresh auth token: something happened")
}
c.updateTachyonAuthToken(token)
validFor, _ := strconv.ParseInt(resp.GetTokenData().GetValidFor(), 10, 64)
c.updateTachyonAuthToken(token, validFor)
c.triggerEvent(events.NewAuthTokenRefreshed(token))
return nil
}

View file

@ -10,26 +10,19 @@ import (
"io"
)
type Cryptor struct {
type AESCTRHelper struct {
AESKey []byte `json:"aes_key"`
HMACKey []byte `json:"hmac_key"`
}
func NewCryptor(aesKey []byte, hmacKey []byte) *Cryptor {
if aesKey != nil && hmacKey != nil {
return &Cryptor{
AESKey: aesKey,
HMACKey: hmacKey,
}
}
aesKey, hmacKey = GenerateKeys()
return &Cryptor{
AESKey: aesKey,
HMACKey: hmacKey,
func NewAESCTRHelper() *AESCTRHelper {
return &AESCTRHelper{
AESKey: GenerateKey(32),
HMACKey: GenerateKey(32),
}
}
func (c *Cryptor) Encrypt(plaintext []byte) ([]byte, error) {
func (c *AESCTRHelper) Encrypt(plaintext []byte) ([]byte, error) {
iv := make([]byte, aes.BlockSize)
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err
@ -40,7 +33,7 @@ func (c *Cryptor) Encrypt(plaintext []byte) ([]byte, error) {
return nil, err
}
ciphertext := make([]byte, len(plaintext))
ciphertext := make([]byte, len(plaintext), len(plaintext)+len(iv)+32)
stream := cipher.NewCTR(block, iv)
stream.XORKeyStream(ciphertext, plaintext)
@ -48,14 +41,12 @@ func (c *Cryptor) Encrypt(plaintext []byte) ([]byte, error) {
mac := hmac.New(sha256.New, c.HMACKey)
mac.Write(ciphertext)
hmac := mac.Sum(nil)
ciphertext = append(ciphertext, hmac...)
ciphertext = append(ciphertext, mac.Sum(nil)...)
return ciphertext, nil
}
func (c *Cryptor) Decrypt(encryptedData []byte) ([]byte, error) {
func (c *AESCTRHelper) Decrypt(encryptedData []byte) ([]byte, error) {
if len(encryptedData) < 48 {
return nil, errors.New("input data is too short")
}

View file

@ -52,10 +52,10 @@ func (t *JWK) GetPublicKey() *ecdsa.PublicKey {
}
// GenerateECDSAKey generates a new ECDSA private key with P-256 curve
func GenerateECDSAKey() (*JWK, error) {
func GenerateECDSAKey() *JWK {
privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return nil, err
panic(fmt.Errorf("failed to generate ecdsa key: %w", err))
}
return &JWK{
KeyType: "EC",
@ -63,5 +63,5 @@ func GenerateECDSAKey() (*JWK, error) {
D: privKey.D.Bytes(),
X: privKey.X.Bytes(),
Y: privKey.Y.Bytes(),
}, nil
}
}

View file

@ -2,25 +2,14 @@ package crypto
import (
"crypto/rand"
"fmt"
)
func GenerateKey(length int) ([]byte, error) {
func GenerateKey(length int) []byte {
key := make([]byte, length)
_, err := rand.Read(key)
if err != nil {
return nil, err
panic(fmt.Errorf("failed to read random bytes: %w", err))
}
return key, nil
}
func GenerateKeys() ([]byte, []byte) {
key, err := GenerateKey(32)
if err != nil {
panic(err)
}
key2, err2 := GenerateKey(32)
if err2 != nil {
panic(err2)
}
return key, key2
return key
}

View file

@ -43,7 +43,7 @@ func (r *RPC) deduplicateUpdate(response *pblite.Response) bool {
}
func (r *RPC) HandleRPCMsg(msg *binary.InternalMessage) {
response, decodeErr := pblite.DecryptInternalMessage(msg, r.client.authData.Cryptor)
response, decodeErr := pblite.DecryptInternalMessage(msg, r.client.authData.RequestCrypto)
if decodeErr != nil {
r.client.Logger.Error().Err(decodeErr).Msg("rpc decrypt msg err")
return

View file

@ -82,10 +82,7 @@ func (c *Client) UploadMedia(data []byte, fileName, mime string) (*binary.MediaC
if mediaType.Type == 0 {
mediaType = MimeToMediaType[strings.Split(mime, "/")[0]]
}
decryptionKey, err := crypto.GenerateKey(32)
if err != nil {
return nil, err
}
decryptionKey := crypto.GenerateKey(32)
cryptor, err := crypto.NewImageCryptor(decryptionKey)
if err != nil {
return nil, err

View file

@ -1,6 +1,7 @@
package libgm
import (
"crypto/x509"
"io"
"time"
@ -23,15 +24,6 @@ type Pairer struct {
}
func (c *Client) NewPairer(keyData *crypto.JWK, refreshQrCodeTime int) (*Pairer, error) {
if keyData == nil {
var err error
keyData, err = crypto.GenerateECDSAKey()
c.updateJWK(keyData)
if err != nil {
c.Logger.Error().Any("data", keyData).Msg(err.Error())
return nil, err
}
}
p := &Pairer{
client: c,
KeyData: keyData,
@ -42,7 +34,27 @@ func (c *Client) NewPairer(keyData *crypto.JWK, refreshQrCodeTime int) (*Pairer,
}
func (p *Pairer) RegisterPhoneRelay() (*binary.RegisterPhoneRelayResponse, error) {
body, _, err := payload.RegisterPhoneRelay(p.KeyData)
key, err := x509.MarshalPKIXPublicKey(p.KeyData.GetPublicKey())
if err != nil {
return nil, err
}
body, err := proto.Marshal(&binary.AuthenticationContainer{
AuthMessage: &binary.AuthMessage{
RequestID: uuid.NewString(),
Network: &payload.Network,
ConfigVersion: payload.ConfigMessage,
},
BrowserDetails: payload.BrowserDetailsMessage,
Data: &binary.AuthenticationContainer_KeyData{
KeyData: &binary.KeyData{
EcdsaKeys: &binary.ECDSAKeys{
Field1: 2,
EncryptedKeys: key,
},
},
},
})
if err != nil {
p.client.Logger.Err(err)
return &binary.RegisterPhoneRelayResponse{}, err

View file

@ -39,8 +39,7 @@ func (c *Client) NewDevicePair(mobile, browser *binary.Device) *pblite.DevicePai
func (c *Client) pairCallback(data *binary.PairedData) error {
tokenData := data.GetTokenData()
c.updateTachyonAuthToken(tokenData.GetTachyonAuthToken())
c.updateTTL(tokenData.GetTTL())
c.updateTachyonAuthToken(tokenData.GetTachyonAuthToken(), tokenData.GetTTL())
devicePair := c.NewDevicePair(data.Mobile, data.Browser)
c.updateDevicePair(devicePair)

View file

@ -1,26 +0,0 @@
package payload
import (
"github.com/google/uuid"
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/pblite"
)
func ReceiveMessages(rpcKey []byte) ([]byte, string, error) {
payload := &binary.ReceiveMessagesRequest{
Auth: &binary.AuthMessage{
RequestID: uuid.New().String(),
TachyonAuthToken: rpcKey,
ConfigVersion: ConfigMessage,
},
Unknown: &binary.ReceiveMessagesRequest_UnknownEmptyObject2{
Unknown: &binary.ReceiveMessagesRequest_UnknownEmptyObject1{},
},
}
jsonData, err := pblite.Marshal(payload)
if err != nil {
return nil, "", err
}
return jsonData, payload.Auth.RequestID, nil
}

View file

@ -1,40 +0,0 @@
package payload
import (
"crypto/x509"
"github.com/google/uuid"
"google.golang.org/protobuf/proto"
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/crypto"
)
func RegisterPhoneRelay(jwk *crypto.JWK) ([]byte, *binary.AuthenticationContainer, error) {
key, err := x509.MarshalPKIXPublicKey(jwk.GetPublicKey())
if err != nil {
return nil, nil, err
}
payloadData := &binary.AuthenticationContainer{
AuthMessage: &binary.AuthMessage{
RequestID: uuid.NewString(),
Network: &Network,
ConfigVersion: ConfigMessage,
},
BrowserDetails: BrowserDetailsMessage,
Data: &binary.AuthenticationContainer_KeyData{
KeyData: &binary.KeyData{
EcdsaKeys: &binary.ECDSAKeys{
Field1: 2,
EncryptedKeys: key,
},
},
},
}
encoded, err4 := proto.Marshal(payloadData)
if err4 != nil {
return nil, payloadData, err4
}
return encoded, payloadData, nil
}

View file

@ -1,28 +0,0 @@
package payload
import (
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/pblite"
)
func RegisterRefresh(sig []byte, requestID string, timestamp int64, browser *binary.Device, tachyonAuthToken []byte) ([]byte, error) {
payload := &binary.RegisterRefreshPayload{
MessageAuth: &binary.AuthMessage{
RequestID: requestID,
TachyonAuthToken: tachyonAuthToken,
ConfigVersion: ConfigMessage,
},
CurrBrowserDevice: browser,
UnixTimestamp: timestamp,
Signature: sig,
EmptyRefreshArr: &binary.EmptyRefreshArr{EmptyArr: &binary.EmptyArr{}},
MessageType: 2, // hmm
}
jsonMessage, serializeErr := pblite.Marshal(payload)
if serializeErr != nil {
return nil, serializeErr
}
return jsonMessage, nil
}

View file

@ -91,7 +91,7 @@ func (sm *SendMessageBuilder) SetTTL(ttl int64) *SendMessageBuilder {
return sm
}
func (sm *SendMessageBuilder) SetEncryptedProtoMessage(message proto.Message, cryptor *crypto.Cryptor) *SendMessageBuilder {
func (sm *SendMessageBuilder) SetEncryptedProtoMessage(message proto.Message, cryptor *crypto.AESCTRHelper) *SendMessageBuilder {
plaintextBytes, err := proto.Marshal(message)
if err != nil {
sm.err = err

View file

@ -39,7 +39,7 @@ type Response struct {
Timestamp string `json:"timestamp"`
}
func DecryptInternalMessage(internalMessage *binary.InternalMessage, cryptor *crypto.Cryptor) (*Response, error) {
func DecryptInternalMessage(internalMessage *binary.InternalMessage, cryptor *crypto.AESCTRHelper) (*Response, error) {
var resp *Response
switch internalMessage.Data.BugleRoute {
case binary.BugleRoute_PairEvent:

View file

@ -12,8 +12,8 @@ import (
func (p *Pairer) GenerateQRCodeData() (string, error) {
urlData := &binary.URLData{
PairingKey: p.pairingKey,
AESKey: p.client.authData.Cryptor.AESKey,
HMACKey: p.client.authData.Cryptor.HMACKey,
AESKey: p.client.authData.RequestCrypto.AESKey,
HMACKey: p.client.authData.RequestCrypto.HMACKey,
}
encodedURLData, err := proto.Marshal(urlData)
if err != nil {

View file

@ -11,9 +11,11 @@ import (
"net/http"
"time"
"github.com/google/uuid"
"github.com/rs/zerolog"
"go.mau.fi/mautrix-gmessages/libgm/events"
"go.mau.fi/mautrix-gmessages/libgm/payload"
"go.mau.fi/mautrix-gmessages/libgm/pblite"
"go.mau.fi/mautrix-gmessages/libgm/binary"
@ -25,7 +27,6 @@ type RPC struct {
http *http.Client
conn io.ReadCloser
stopping bool
rpcSessionId string
listenID int
skipCount int
@ -34,22 +35,33 @@ type RPC struct {
recentUpdatesPtr int
}
func (r *RPC) ListenReceiveMessages(payload []byte) {
func (r *RPC) ListenReceiveMessages() {
r.listenID++
listenID := r.listenID
errored := true
listenReqID := uuid.NewString()
for r.listenID == listenID {
if r.client.authData.DevicePair != nil && r.client.authData.AuthenticatedAt.Add(20*time.Hour).Before(time.Now()) {
r.client.Logger.Debug().Msg("Refreshing auth token before starting new long-polling request")
err := r.client.refreshAuthToken()
if err != nil {
r.client.Logger.Err(err).Msg("Error refreshing auth token")
r.client.triggerEvent(&events.ListenFatalError{Error: fmt.Errorf("failed to refresh auth token: %w", err)})
return
}
}
r.client.Logger.Debug().Msg("Starting new long-polling request")
req, err := http.NewRequest("POST", util.ReceiveMessagesURL, bytes.NewReader(payload))
receivePayload, err := pblite.Marshal(&binary.ReceiveMessagesRequest{
Auth: &binary.AuthMessage{
RequestID: listenReqID,
TachyonAuthToken: r.client.authData.TachyonAuthToken,
ConfigVersion: payload.ConfigMessage,
},
Unknown: &binary.ReceiveMessagesRequest_UnknownEmptyObject2{
Unknown: &binary.ReceiveMessagesRequest_UnknownEmptyObject1{},
},
})
if err != nil {
panic(fmt.Errorf("Error marshaling request: %v", err))
}
req, err := http.NewRequest(http.MethodPost, util.ReceiveMessagesURL, bytes.NewReader(receivePayload))
if err != nil {
panic(fmt.Errorf("Error creating request: %v", err))
}

View file

@ -91,11 +91,11 @@ func (s *SessionHandler) buildMessage(actionType binary.ActionType, encryptedDat
tmpMessage := payload.NewSendMessageBuilder(token, pairedDevice, requestID, sessionId).SetRoute(routeInfo.Action).SetSessionId(s.sessionID)
if encryptedData != nil {
tmpMessage.SetEncryptedProtoMessage(encryptedData, s.client.authData.Cryptor)
tmpMessage.SetEncryptedProtoMessage(encryptedData, s.client.authData.RequestCrypto)
}
if routeInfo.UseTTL {
tmpMessage.SetTTL(s.client.authData.TTL)
tmpMessage.SetTTL(s.client.authData.TachyonTTL)
}
message, buildErr := tmpMessage.Build()

View file

@ -55,7 +55,6 @@ func (c *Client) handleClientReady(newSessionId string) {
if convErr != nil {
panic(convErr)
}
c.Logger.Debug().Any("conversations", conversations).Msg("got conversations")
notifyErr := c.NotifyDittoActivity()
if notifyErr != nil {
panic(notifyErr)

View file

@ -42,7 +42,6 @@ import (
"go.mau.fi/mautrix-gmessages/database"
"go.mau.fi/mautrix-gmessages/libgm"
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/crypto"
"go.mau.fi/mautrix-gmessages/libgm/events"
)
@ -393,9 +392,7 @@ var ErrAlreadyLoggedIn = errors.New("already logged in")
func (user *User) createClient() {
if user.Session == nil {
user.Session = &libgm.AuthData{
Cryptor: crypto.NewCryptor(nil, nil),
}
user.Session = libgm.NewAuthData()
}
user.Client = libgm.NewClient(user.Session, user.zlog.With().Str("component", "libgm").Logger())
user.Client.SetEventHandler(user.syncHandleEvent)