From 3fefda3a965f2fc4d9b483c18dd07e4c6c6bad72 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 16 Jul 2023 14:36:13 +0300 Subject: [PATCH] Refactor more things --- gmtest/main.go | 5 +- libgm/client.go | 139 ++++++++++++---------------- libgm/crypto/cryptor.go | 27 ++---- libgm/crypto/ecdsa.go | 6 +- libgm/crypto/generate.go | 19 +--- libgm/event_handler.go | 2 +- libgm/image_builder.go | 5 +- libgm/pair.go | 32 +++++-- libgm/pairing_handler.go | 3 +- libgm/payload/receiveMessages.go | 26 ------ libgm/payload/registerPhoneRelay.go | 40 -------- libgm/payload/registerRefresh.go | 28 ------ libgm/payload/sendMessage.go | 2 +- libgm/pblite/internal.go | 2 +- libgm/qr.go | 4 +- libgm/rpc.go | 44 +++++---- libgm/session_handler.go | 4 +- libgm/updates_handler.go | 1 - user.go | 5 +- 19 files changed, 138 insertions(+), 256 deletions(-) delete mode 100644 libgm/payload/receiveMessages.go delete mode 100644 libgm/payload/registerPhoneRelay.go delete mode 100644 libgm/payload/registerRefresh.go diff --git a/gmtest/main.go b/gmtest/main.go index d0dbfe2..95b4939 100644 --- a/gmtest/main.go +++ b/gmtest/main.go @@ -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()) diff --git a/libgm/client.go b/libgm/client.go index 06cb710..8ff4889 100644 --- a/libgm/client.go +++ b/libgm/client.go @@ -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"` - DevicePair *pblite.DevicePair `json:"device_pair,omitempty"` - Cryptor *crypto.Cryptor `json:"crypto,omitempty"` - WebEncryptionKey []byte `json:"web_encryption_key,omitempty"` - JWK *crypto.JWK `json:"jwk,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"` + // 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"` } + +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) - } + 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") -} - -func (c *Client) updateTTL(ttl int64) { - c.authData.TTL = ttl - c.Logger.Debug().Any("ttl", ttl).Msg("Updated TTL") + validForDuration := time.Duration(validFor) * time.Microsecond + if validForDuration == 0 { + validForDuration = 24 * time.Hour + } + 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 } diff --git a/libgm/crypto/cryptor.go b/libgm/crypto/cryptor.go index e4f28cb..77a7107 100644 --- a/libgm/crypto/cryptor.go +++ b/libgm/crypto/cryptor.go @@ -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") } diff --git a/libgm/crypto/ecdsa.go b/libgm/crypto/ecdsa.go index 94ae6cd..b1edf66 100644 --- a/libgm/crypto/ecdsa.go +++ b/libgm/crypto/ecdsa.go @@ -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 + } } diff --git a/libgm/crypto/generate.go b/libgm/crypto/generate.go index fcd5e80..23db8ea 100644 --- a/libgm/crypto/generate.go +++ b/libgm/crypto/generate.go @@ -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 } diff --git a/libgm/event_handler.go b/libgm/event_handler.go index 9852e0a..abf8faf 100644 --- a/libgm/event_handler.go +++ b/libgm/event_handler.go @@ -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 diff --git a/libgm/image_builder.go b/libgm/image_builder.go index d0affbf..b66de9e 100644 --- a/libgm/image_builder.go +++ b/libgm/image_builder.go @@ -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 diff --git a/libgm/pair.go b/libgm/pair.go index 271c291..0f1e657 100644 --- a/libgm/pair.go +++ b/libgm/pair.go @@ -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 diff --git a/libgm/pairing_handler.go b/libgm/pairing_handler.go index 94eea7b..8e90a34 100644 --- a/libgm/pairing_handler.go +++ b/libgm/pairing_handler.go @@ -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) diff --git a/libgm/payload/receiveMessages.go b/libgm/payload/receiveMessages.go deleted file mode 100644 index 8233445..0000000 --- a/libgm/payload/receiveMessages.go +++ /dev/null @@ -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 -} diff --git a/libgm/payload/registerPhoneRelay.go b/libgm/payload/registerPhoneRelay.go deleted file mode 100644 index ddb35b6..0000000 --- a/libgm/payload/registerPhoneRelay.go +++ /dev/null @@ -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 -} diff --git a/libgm/payload/registerRefresh.go b/libgm/payload/registerRefresh.go deleted file mode 100644 index 25bc42a..0000000 --- a/libgm/payload/registerRefresh.go +++ /dev/null @@ -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 -} diff --git a/libgm/payload/sendMessage.go b/libgm/payload/sendMessage.go index ef70fb2..63b826c 100644 --- a/libgm/payload/sendMessage.go +++ b/libgm/payload/sendMessage.go @@ -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 diff --git a/libgm/pblite/internal.go b/libgm/pblite/internal.go index 910a5ee..81e19e8 100644 --- a/libgm/pblite/internal.go +++ b/libgm/pblite/internal.go @@ -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: diff --git a/libgm/qr.go b/libgm/qr.go index 1ac0819..7a17e51 100644 --- a/libgm/qr.go +++ b/libgm/qr.go @@ -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 { diff --git a/libgm/rpc.go b/libgm/rpc.go index 8d04de9..dcd896d 100644 --- a/libgm/rpc.go +++ b/libgm/rpc.go @@ -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" @@ -21,12 +23,11 @@ import ( ) type RPC struct { - client *Client - http *http.Client - conn io.ReadCloser - stopping bool - rpcSessionId string - listenID int + client *Client + http *http.Client + conn io.ReadCloser + stopping bool + 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 - } + 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)) } diff --git a/libgm/session_handler.go b/libgm/session_handler.go index 771dbcc..064c72a 100644 --- a/libgm/session_handler.go +++ b/libgm/session_handler.go @@ -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() diff --git a/libgm/updates_handler.go b/libgm/updates_handler.go index 1d91af3..83586c2 100644 --- a/libgm/updates_handler.go +++ b/libgm/updates_handler.go @@ -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) diff --git a/user.go b/user.go index f08ad0b..6a49ed8 100644 --- a/user.go +++ b/user.go @@ -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)