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

View file

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

View file

@ -10,26 +10,19 @@ import (
"io" "io"
) )
type Cryptor struct { type AESCTRHelper struct {
AESKey []byte `json:"aes_key"` AESKey []byte `json:"aes_key"`
HMACKey []byte `json:"hmac_key"` HMACKey []byte `json:"hmac_key"`
} }
func NewCryptor(aesKey []byte, hmacKey []byte) *Cryptor { func NewAESCTRHelper() *AESCTRHelper {
if aesKey != nil && hmacKey != nil { return &AESCTRHelper{
return &Cryptor{ AESKey: GenerateKey(32),
AESKey: aesKey, HMACKey: GenerateKey(32),
HMACKey: hmacKey,
}
}
aesKey, hmacKey = GenerateKeys()
return &Cryptor{
AESKey: aesKey,
HMACKey: hmacKey,
} }
} }
func (c *Cryptor) Encrypt(plaintext []byte) ([]byte, error) { func (c *AESCTRHelper) Encrypt(plaintext []byte) ([]byte, error) {
iv := make([]byte, aes.BlockSize) iv := make([]byte, aes.BlockSize)
if _, err := io.ReadFull(rand.Reader, iv); err != nil { if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err return nil, err
@ -40,7 +33,7 @@ func (c *Cryptor) Encrypt(plaintext []byte) ([]byte, error) {
return nil, err return nil, err
} }
ciphertext := make([]byte, len(plaintext)) ciphertext := make([]byte, len(plaintext), len(plaintext)+len(iv)+32)
stream := cipher.NewCTR(block, iv) stream := cipher.NewCTR(block, iv)
stream.XORKeyStream(ciphertext, plaintext) stream.XORKeyStream(ciphertext, plaintext)
@ -48,14 +41,12 @@ func (c *Cryptor) Encrypt(plaintext []byte) ([]byte, error) {
mac := hmac.New(sha256.New, c.HMACKey) mac := hmac.New(sha256.New, c.HMACKey)
mac.Write(ciphertext) mac.Write(ciphertext)
hmac := mac.Sum(nil) ciphertext = append(ciphertext, mac.Sum(nil)...)
ciphertext = append(ciphertext, hmac...)
return ciphertext, nil return ciphertext, nil
} }
func (c *Cryptor) Decrypt(encryptedData []byte) ([]byte, error) { func (c *AESCTRHelper) Decrypt(encryptedData []byte) ([]byte, error) {
if len(encryptedData) < 48 { if len(encryptedData) < 48 {
return nil, errors.New("input data is too short") 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 // 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) privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil { if err != nil {
return nil, err panic(fmt.Errorf("failed to generate ecdsa key: %w", err))
} }
return &JWK{ return &JWK{
KeyType: "EC", KeyType: "EC",
@ -63,5 +63,5 @@ func GenerateECDSAKey() (*JWK, error) {
D: privKey.D.Bytes(), D: privKey.D.Bytes(),
X: privKey.X.Bytes(), X: privKey.X.Bytes(),
Y: privKey.Y.Bytes(), Y: privKey.Y.Bytes(),
}, nil }
} }

View file

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

View file

@ -43,7 +43,7 @@ func (r *RPC) deduplicateUpdate(response *pblite.Response) bool {
} }
func (r *RPC) HandleRPCMsg(msg *binary.InternalMessage) { 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 { if decodeErr != nil {
r.client.Logger.Error().Err(decodeErr).Msg("rpc decrypt msg err") r.client.Logger.Error().Err(decodeErr).Msg("rpc decrypt msg err")
return return

View file

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

View file

@ -1,6 +1,7 @@
package libgm package libgm
import ( import (
"crypto/x509"
"io" "io"
"time" "time"
@ -23,15 +24,6 @@ type Pairer struct {
} }
func (c *Client) NewPairer(keyData *crypto.JWK, refreshQrCodeTime int) (*Pairer, error) { 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{ p := &Pairer{
client: c, client: c,
KeyData: keyData, KeyData: keyData,
@ -42,7 +34,27 @@ func (c *Client) NewPairer(keyData *crypto.JWK, refreshQrCodeTime int) (*Pairer,
} }
func (p *Pairer) RegisterPhoneRelay() (*binary.RegisterPhoneRelayResponse, error) { 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 { if err != nil {
p.client.Logger.Err(err) p.client.Logger.Err(err)
return &binary.RegisterPhoneRelayResponse{}, 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 { func (c *Client) pairCallback(data *binary.PairedData) error {
tokenData := data.GetTokenData() tokenData := data.GetTokenData()
c.updateTachyonAuthToken(tokenData.GetTachyonAuthToken()) c.updateTachyonAuthToken(tokenData.GetTachyonAuthToken(), tokenData.GetTTL())
c.updateTTL(tokenData.GetTTL())
devicePair := c.NewDevicePair(data.Mobile, data.Browser) devicePair := c.NewDevicePair(data.Mobile, data.Browser)
c.updateDevicePair(devicePair) 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 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) plaintextBytes, err := proto.Marshal(message)
if err != nil { if err != nil {
sm.err = err sm.err = err

View file

@ -39,7 +39,7 @@ type Response struct {
Timestamp string `json:"timestamp"` 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 var resp *Response
switch internalMessage.Data.BugleRoute { switch internalMessage.Data.BugleRoute {
case binary.BugleRoute_PairEvent: case binary.BugleRoute_PairEvent:

View file

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

View file

@ -11,9 +11,11 @@ import (
"net/http" "net/http"
"time" "time"
"github.com/google/uuid"
"github.com/rs/zerolog" "github.com/rs/zerolog"
"go.mau.fi/mautrix-gmessages/libgm/events" "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/pblite"
"go.mau.fi/mautrix-gmessages/libgm/binary" "go.mau.fi/mautrix-gmessages/libgm/binary"
@ -21,12 +23,11 @@ import (
) )
type RPC struct { type RPC struct {
client *Client client *Client
http *http.Client http *http.Client
conn io.ReadCloser conn io.ReadCloser
stopping bool stopping bool
rpcSessionId string listenID int
listenID int
skipCount int skipCount int
@ -34,22 +35,33 @@ type RPC struct {
recentUpdatesPtr int recentUpdatesPtr int
} }
func (r *RPC) ListenReceiveMessages(payload []byte) { func (r *RPC) ListenReceiveMessages() {
r.listenID++ r.listenID++
listenID := r.listenID listenID := r.listenID
errored := true errored := true
listenReqID := uuid.NewString()
for r.listenID == listenID { for r.listenID == listenID {
if r.client.authData.DevicePair != nil && r.client.authData.AuthenticatedAt.Add(20*time.Hour).Before(time.Now()) { err := r.client.refreshAuthToken()
r.client.Logger.Debug().Msg("Refreshing auth token before starting new long-polling request") if err != nil {
err := r.client.refreshAuthToken() r.client.Logger.Err(err).Msg("Error refreshing auth token")
if err != nil { r.client.triggerEvent(&events.ListenFatalError{Error: fmt.Errorf("failed to refresh auth token: %w", err)})
r.client.Logger.Err(err).Msg("Error refreshing auth token") return
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") 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 { if err != nil {
panic(fmt.Errorf("Error creating request: %v", err)) 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) tmpMessage := payload.NewSendMessageBuilder(token, pairedDevice, requestID, sessionId).SetRoute(routeInfo.Action).SetSessionId(s.sessionID)
if encryptedData != nil { if encryptedData != nil {
tmpMessage.SetEncryptedProtoMessage(encryptedData, s.client.authData.Cryptor) tmpMessage.SetEncryptedProtoMessage(encryptedData, s.client.authData.RequestCrypto)
} }
if routeInfo.UseTTL { if routeInfo.UseTTL {
tmpMessage.SetTTL(s.client.authData.TTL) tmpMessage.SetTTL(s.client.authData.TachyonTTL)
} }
message, buildErr := tmpMessage.Build() message, buildErr := tmpMessage.Build()

View file

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

View file

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