Handle HTTP error responses properly

This commit is contained in:
Tulir Asokan 2023-09-04 14:24:45 +03:00
parent 88ba4b12b6
commit dc2d34127f
10 changed files with 365 additions and 102 deletions

View file

@ -30,6 +30,7 @@ const (
GMNotConnected status.BridgeStateErrorCode = "gm-not-connected" GMNotConnected status.BridgeStateErrorCode = "gm-not-connected"
GMConnecting status.BridgeStateErrorCode = "gm-connecting" GMConnecting status.BridgeStateErrorCode = "gm-connecting"
GMConnectionFailed status.BridgeStateErrorCode = "gm-connection-failed" GMConnectionFailed status.BridgeStateErrorCode = "gm-connection-failed"
GMPingFailed status.BridgeStateErrorCode = "gm-ping-failed"
GMBrowserInactive status.BridgeStateErrorCode = "gm-browser-inactive" GMBrowserInactive status.BridgeStateErrorCode = "gm-browser-inactive"
GMBrowserInactiveTimeout status.BridgeStateErrorCode = "gm-browser-inactive-timeout" GMBrowserInactiveTimeout status.BridgeStateErrorCode = "gm-browser-inactive-timeout"

View file

@ -142,6 +142,9 @@ func (c *Client) postConnect() {
err := c.SetActiveSession() err := c.SetActiveSession()
if err != nil { if err != nil {
c.Logger.Err(err).Msg("Failed to set active session") c.Logger.Err(err).Msg("Failed to set active session")
c.triggerEvent(&events.PingFailed{
Error: fmt.Errorf("failed to set active session: %w", err),
})
return return
} }

View file

@ -1,6 +1,7 @@
package events package events
import ( import (
"errors"
"fmt" "fmt"
"net/http" "net/http"
@ -14,9 +15,49 @@ type ClientReady struct {
type AuthTokenRefreshed struct{} type AuthTokenRefreshed struct{}
var ErrRequestedEntityNotFound = RequestError{
Data: &gmproto.ErrorResponse{
Type: 5,
Message: "Requested entity was not found.",
Class: []*gmproto.ErrorResponse_ErrorClass{{
Class: "type.googleapis.com/google.internal.communications.instantmessaging.v1.TachyonError",
}},
},
}
type RequestError struct {
Data *gmproto.ErrorResponse
HTTP *HTTPError
}
func (re RequestError) Unwrap() error {
if re.HTTP == nil {
return nil
}
return *re.HTTP
}
func (re RequestError) Error() string {
if re.HTTP == nil {
return fmt.Sprintf("%d: %s", re.Data.Type, re.Data.Message)
}
return fmt.Sprintf("HTTP %d: %d: %s", re.HTTP.Resp.StatusCode, re.Data.Type, re.Data.Message)
}
func (re RequestError) Is(other error) bool {
otherRe, ok := other.(RequestError)
if !ok {
return errors.Is(*re.HTTP, other)
}
return otherRe.Data.GetType() == re.Data.GetType() &&
otherRe.Data.GetMessage() == re.Data.GetMessage()
// TODO check class?
}
type HTTPError struct { type HTTPError struct {
Action string Action string
Resp *http.Response Resp *http.Response
Body []byte
} }
func (he HTTPError) Error() string { func (he HTTPError) Error() string {
@ -39,3 +80,7 @@ type ListenRecovered struct{}
type PhoneNotResponding struct{} type PhoneNotResponding struct{}
type PhoneRespondingAgain struct{} type PhoneRespondingAgain struct{}
type PingFailed struct {
Error error
}

View file

@ -998,6 +998,69 @@ func (x *WebEncryptionKeyResponse) GetKey() []byte {
return nil return nil
} }
type ErrorResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Type int64 `protobuf:"varint,1,opt,name=type,proto3" json:"type,omitempty"` // 5?
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
Class []*ErrorResponse_ErrorClass `protobuf:"bytes,3,rep,name=class,proto3" json:"class,omitempty"`
}
func (x *ErrorResponse) Reset() {
*x = ErrorResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_authentication_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ErrorResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ErrorResponse) ProtoMessage() {}
func (x *ErrorResponse) ProtoReflect() protoreflect.Message {
mi := &file_authentication_proto_msgTypes[13]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ErrorResponse.ProtoReflect.Descriptor instead.
func (*ErrorResponse) Descriptor() ([]byte, []int) {
return file_authentication_proto_rawDescGZIP(), []int{13}
}
func (x *ErrorResponse) GetType() int64 {
if x != nil {
return x.Type
}
return 0
}
func (x *ErrorResponse) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
func (x *ErrorResponse) GetClass() []*ErrorResponse_ErrorClass {
if x != nil {
return x.Class
}
return nil
}
type ECDSAKeys struct { type ECDSAKeys struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@ -1010,7 +1073,7 @@ type ECDSAKeys struct {
func (x *ECDSAKeys) Reset() { func (x *ECDSAKeys) Reset() {
*x = ECDSAKeys{} *x = ECDSAKeys{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_authentication_proto_msgTypes[13] mi := &file_authentication_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -1023,7 +1086,7 @@ func (x *ECDSAKeys) String() string {
func (*ECDSAKeys) ProtoMessage() {} func (*ECDSAKeys) ProtoMessage() {}
func (x *ECDSAKeys) ProtoReflect() protoreflect.Message { func (x *ECDSAKeys) ProtoReflect() protoreflect.Message {
mi := &file_authentication_proto_msgTypes[13] mi := &file_authentication_proto_msgTypes[14]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -1036,7 +1099,7 @@ func (x *ECDSAKeys) ProtoReflect() protoreflect.Message {
// Deprecated: Use ECDSAKeys.ProtoReflect.Descriptor instead. // Deprecated: Use ECDSAKeys.ProtoReflect.Descriptor instead.
func (*ECDSAKeys) Descriptor() ([]byte, []int) { func (*ECDSAKeys) Descriptor() ([]byte, []int) {
return file_authentication_proto_rawDescGZIP(), []int{13} return file_authentication_proto_rawDescGZIP(), []int{14}
} }
func (x *ECDSAKeys) GetField1() int64 { func (x *ECDSAKeys) GetField1() int64 {
@ -1064,7 +1127,7 @@ type CurrentDeviceData struct {
func (x *CurrentDeviceData) Reset() { func (x *CurrentDeviceData) Reset() {
*x = CurrentDeviceData{} *x = CurrentDeviceData{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_authentication_proto_msgTypes[14] mi := &file_authentication_proto_msgTypes[15]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -1077,7 +1140,7 @@ func (x *CurrentDeviceData) String() string {
func (*CurrentDeviceData) ProtoMessage() {} func (*CurrentDeviceData) ProtoMessage() {}
func (x *CurrentDeviceData) ProtoReflect() protoreflect.Message { func (x *CurrentDeviceData) ProtoReflect() protoreflect.Message {
mi := &file_authentication_proto_msgTypes[14] mi := &file_authentication_proto_msgTypes[15]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -1090,7 +1153,7 @@ func (x *CurrentDeviceData) ProtoReflect() protoreflect.Message {
// Deprecated: Use CurrentDeviceData.ProtoReflect.Descriptor instead. // Deprecated: Use CurrentDeviceData.ProtoReflect.Descriptor instead.
func (*CurrentDeviceData) Descriptor() ([]byte, []int) { func (*CurrentDeviceData) Descriptor() ([]byte, []int) {
return file_authentication_proto_rawDescGZIP(), []int{14} return file_authentication_proto_rawDescGZIP(), []int{15}
} }
func (x *CurrentDeviceData) GetBrowser() *Device { func (x *CurrentDeviceData) GetBrowser() *Device {
@ -1114,7 +1177,7 @@ type KeyData struct {
func (x *KeyData) Reset() { func (x *KeyData) Reset() {
*x = KeyData{} *x = KeyData{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_authentication_proto_msgTypes[15] mi := &file_authentication_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -1127,7 +1190,7 @@ func (x *KeyData) String() string {
func (*KeyData) ProtoMessage() {} func (*KeyData) ProtoMessage() {}
func (x *KeyData) ProtoReflect() protoreflect.Message { func (x *KeyData) ProtoReflect() protoreflect.Message {
mi := &file_authentication_proto_msgTypes[15] mi := &file_authentication_proto_msgTypes[16]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -1140,7 +1203,7 @@ func (x *KeyData) ProtoReflect() protoreflect.Message {
// Deprecated: Use KeyData.ProtoReflect.Descriptor instead. // Deprecated: Use KeyData.ProtoReflect.Descriptor instead.
func (*KeyData) Descriptor() ([]byte, []int) { func (*KeyData) Descriptor() ([]byte, []int) {
return file_authentication_proto_rawDescGZIP(), []int{15} return file_authentication_proto_rawDescGZIP(), []int{16}
} }
func (x *KeyData) GetMobile() *Device { func (x *KeyData) GetMobile() *Device {
@ -1183,7 +1246,7 @@ type WebAuthKey struct {
func (x *WebAuthKey) Reset() { func (x *WebAuthKey) Reset() {
*x = WebAuthKey{} *x = WebAuthKey{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_authentication_proto_msgTypes[16] mi := &file_authentication_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -1196,7 +1259,7 @@ func (x *WebAuthKey) String() string {
func (*WebAuthKey) ProtoMessage() {} func (*WebAuthKey) ProtoMessage() {}
func (x *WebAuthKey) ProtoReflect() protoreflect.Message { func (x *WebAuthKey) ProtoReflect() protoreflect.Message {
mi := &file_authentication_proto_msgTypes[16] mi := &file_authentication_proto_msgTypes[17]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -1209,7 +1272,7 @@ func (x *WebAuthKey) ProtoReflect() protoreflect.Message {
// Deprecated: Use WebAuthKey.ProtoReflect.Descriptor instead. // Deprecated: Use WebAuthKey.ProtoReflect.Descriptor instead.
func (*WebAuthKey) Descriptor() ([]byte, []int) { func (*WebAuthKey) Descriptor() ([]byte, []int) {
return file_authentication_proto_rawDescGZIP(), []int{16} return file_authentication_proto_rawDescGZIP(), []int{17}
} }
func (x *WebAuthKey) GetWebAuthKey() []byte { func (x *WebAuthKey) GetWebAuthKey() []byte {
@ -1239,7 +1302,7 @@ type URLData struct {
func (x *URLData) Reset() { func (x *URLData) Reset() {
*x = URLData{} *x = URLData{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_authentication_proto_msgTypes[17] mi := &file_authentication_proto_msgTypes[18]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -1252,7 +1315,7 @@ func (x *URLData) String() string {
func (*URLData) ProtoMessage() {} func (*URLData) ProtoMessage() {}
func (x *URLData) ProtoReflect() protoreflect.Message { func (x *URLData) ProtoReflect() protoreflect.Message {
mi := &file_authentication_proto_msgTypes[17] mi := &file_authentication_proto_msgTypes[18]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -1265,7 +1328,7 @@ func (x *URLData) ProtoReflect() protoreflect.Message {
// Deprecated: Use URLData.ProtoReflect.Descriptor instead. // Deprecated: Use URLData.ProtoReflect.Descriptor instead.
func (*URLData) Descriptor() ([]byte, []int) { func (*URLData) Descriptor() ([]byte, []int) {
return file_authentication_proto_rawDescGZIP(), []int{17} return file_authentication_proto_rawDescGZIP(), []int{18}
} }
func (x *URLData) GetPairingKey() []byte { func (x *URLData) GetPairingKey() []byte {
@ -1301,7 +1364,7 @@ type TokenData struct {
func (x *TokenData) Reset() { func (x *TokenData) Reset() {
*x = TokenData{} *x = TokenData{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_authentication_proto_msgTypes[18] mi := &file_authentication_proto_msgTypes[19]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -1314,7 +1377,7 @@ func (x *TokenData) String() string {
func (*TokenData) ProtoMessage() {} func (*TokenData) ProtoMessage() {}
func (x *TokenData) ProtoReflect() protoreflect.Message { func (x *TokenData) ProtoReflect() protoreflect.Message {
mi := &file_authentication_proto_msgTypes[18] mi := &file_authentication_proto_msgTypes[19]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -1327,7 +1390,7 @@ func (x *TokenData) ProtoReflect() protoreflect.Message {
// Deprecated: Use TokenData.ProtoReflect.Descriptor instead. // Deprecated: Use TokenData.ProtoReflect.Descriptor instead.
func (*TokenData) Descriptor() ([]byte, []int) { func (*TokenData) Descriptor() ([]byte, []int) {
return file_authentication_proto_rawDescGZIP(), []int{18} return file_authentication_proto_rawDescGZIP(), []int{19}
} }
func (x *TokenData) GetTachyonAuthToken() []byte { func (x *TokenData) GetTachyonAuthToken() []byte {
@ -1357,7 +1420,7 @@ type PairedData struct {
func (x *PairedData) Reset() { func (x *PairedData) Reset() {
*x = PairedData{} *x = PairedData{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_authentication_proto_msgTypes[19] mi := &file_authentication_proto_msgTypes[20]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -1370,7 +1433,7 @@ func (x *PairedData) String() string {
func (*PairedData) ProtoMessage() {} func (*PairedData) ProtoMessage() {}
func (x *PairedData) ProtoReflect() protoreflect.Message { func (x *PairedData) ProtoReflect() protoreflect.Message {
mi := &file_authentication_proto_msgTypes[19] mi := &file_authentication_proto_msgTypes[20]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -1383,7 +1446,7 @@ func (x *PairedData) ProtoReflect() protoreflect.Message {
// Deprecated: Use PairedData.ProtoReflect.Descriptor instead. // Deprecated: Use PairedData.ProtoReflect.Descriptor instead.
func (*PairedData) Descriptor() ([]byte, []int) { func (*PairedData) Descriptor() ([]byte, []int) {
return file_authentication_proto_rawDescGZIP(), []int{19} return file_authentication_proto_rawDescGZIP(), []int{20}
} }
func (x *PairedData) GetMobile() *Device { func (x *PairedData) GetMobile() *Device {
@ -1418,7 +1481,7 @@ type RevokePairData struct {
func (x *RevokePairData) Reset() { func (x *RevokePairData) Reset() {
*x = RevokePairData{} *x = RevokePairData{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_authentication_proto_msgTypes[20] mi := &file_authentication_proto_msgTypes[21]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -1431,7 +1494,7 @@ func (x *RevokePairData) String() string {
func (*RevokePairData) ProtoMessage() {} func (*RevokePairData) ProtoMessage() {}
func (x *RevokePairData) ProtoReflect() protoreflect.Message { func (x *RevokePairData) ProtoReflect() protoreflect.Message {
mi := &file_authentication_proto_msgTypes[20] mi := &file_authentication_proto_msgTypes[21]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -1444,7 +1507,7 @@ func (x *RevokePairData) ProtoReflect() protoreflect.Message {
// Deprecated: Use RevokePairData.ProtoReflect.Descriptor instead. // Deprecated: Use RevokePairData.ProtoReflect.Descriptor instead.
func (*RevokePairData) Descriptor() ([]byte, []int) { func (*RevokePairData) Descriptor() ([]byte, []int) {
return file_authentication_proto_rawDescGZIP(), []int{20} return file_authentication_proto_rawDescGZIP(), []int{21}
} }
func (x *RevokePairData) GetRevokedDevice() *Device { func (x *RevokePairData) GetRevokedDevice() *Device {
@ -1465,7 +1528,7 @@ type RegisterRefreshRequest_NestedEmptyArr struct {
func (x *RegisterRefreshRequest_NestedEmptyArr) Reset() { func (x *RegisterRefreshRequest_NestedEmptyArr) Reset() {
*x = RegisterRefreshRequest_NestedEmptyArr{} *x = RegisterRefreshRequest_NestedEmptyArr{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_authentication_proto_msgTypes[21] mi := &file_authentication_proto_msgTypes[22]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -1478,7 +1541,7 @@ func (x *RegisterRefreshRequest_NestedEmptyArr) String() string {
func (*RegisterRefreshRequest_NestedEmptyArr) ProtoMessage() {} func (*RegisterRefreshRequest_NestedEmptyArr) ProtoMessage() {}
func (x *RegisterRefreshRequest_NestedEmptyArr) ProtoReflect() protoreflect.Message { func (x *RegisterRefreshRequest_NestedEmptyArr) ProtoReflect() protoreflect.Message {
mi := &file_authentication_proto_msgTypes[21] mi := &file_authentication_proto_msgTypes[22]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -1513,7 +1576,7 @@ type RegisterRefreshResponse_AuthKeyData struct {
func (x *RegisterRefreshResponse_AuthKeyData) Reset() { func (x *RegisterRefreshResponse_AuthKeyData) Reset() {
*x = RegisterRefreshResponse_AuthKeyData{} *x = RegisterRefreshResponse_AuthKeyData{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_authentication_proto_msgTypes[22] mi := &file_authentication_proto_msgTypes[23]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -1526,7 +1589,7 @@ func (x *RegisterRefreshResponse_AuthKeyData) String() string {
func (*RegisterRefreshResponse_AuthKeyData) ProtoMessage() {} func (*RegisterRefreshResponse_AuthKeyData) ProtoMessage() {}
func (x *RegisterRefreshResponse_AuthKeyData) ProtoReflect() protoreflect.Message { func (x *RegisterRefreshResponse_AuthKeyData) ProtoReflect() protoreflect.Message {
mi := &file_authentication_proto_msgTypes[22] mi := &file_authentication_proto_msgTypes[23]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -1568,7 +1631,7 @@ type RegisterPhoneRelayResponse_AuthKeyData struct {
func (x *RegisterPhoneRelayResponse_AuthKeyData) Reset() { func (x *RegisterPhoneRelayResponse_AuthKeyData) Reset() {
*x = RegisterPhoneRelayResponse_AuthKeyData{} *x = RegisterPhoneRelayResponse_AuthKeyData{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_authentication_proto_msgTypes[23] mi := &file_authentication_proto_msgTypes[24]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -1581,7 +1644,7 @@ func (x *RegisterPhoneRelayResponse_AuthKeyData) String() string {
func (*RegisterPhoneRelayResponse_AuthKeyData) ProtoMessage() {} func (*RegisterPhoneRelayResponse_AuthKeyData) ProtoMessage() {}
func (x *RegisterPhoneRelayResponse_AuthKeyData) ProtoReflect() protoreflect.Message { func (x *RegisterPhoneRelayResponse_AuthKeyData) ProtoReflect() protoreflect.Message {
mi := &file_authentication_proto_msgTypes[23] mi := &file_authentication_proto_msgTypes[24]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -1611,6 +1674,53 @@ func (x *RegisterPhoneRelayResponse_AuthKeyData) GetValidFor() int64 {
return 0 return 0
} }
type ErrorResponse_ErrorClass struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Class string `protobuf:"bytes,1,opt,name=class,proto3" json:"class,omitempty"` // 2: {1: 1}
}
func (x *ErrorResponse_ErrorClass) Reset() {
*x = ErrorResponse_ErrorClass{}
if protoimpl.UnsafeEnabled {
mi := &file_authentication_proto_msgTypes[25]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ErrorResponse_ErrorClass) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ErrorResponse_ErrorClass) ProtoMessage() {}
func (x *ErrorResponse_ErrorClass) ProtoReflect() protoreflect.Message {
mi := &file_authentication_proto_msgTypes[25]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ErrorResponse_ErrorClass.ProtoReflect.Descriptor instead.
func (*ErrorResponse_ErrorClass) Descriptor() ([]byte, []int) {
return file_authentication_proto_rawDescGZIP(), []int{13, 0}
}
func (x *ErrorResponse_ErrorClass) GetClass() string {
if x != nil {
return x.Class
}
return ""
}
var File_authentication_proto protoreflect.FileDescriptor var File_authentication_proto protoreflect.FileDescriptor
//go:embed authentication.pb.raw //go:embed authentication.pb.raw
@ -1629,7 +1739,7 @@ func file_authentication_proto_rawDescGZIP() []byte {
} }
var file_authentication_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_authentication_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
var file_authentication_proto_msgTypes = make([]protoimpl.MessageInfo, 24) var file_authentication_proto_msgTypes = make([]protoimpl.MessageInfo, 26)
var file_authentication_proto_goTypes = []interface{}{ var file_authentication_proto_goTypes = []interface{}{
(BrowserType)(0), // 0: authentication.BrowserType (BrowserType)(0), // 0: authentication.BrowserType
(DeviceType)(0), // 1: authentication.DeviceType (DeviceType)(0), // 1: authentication.DeviceType
@ -1646,53 +1756,56 @@ var file_authentication_proto_goTypes = []interface{}{
(*CoordinateMessage)(nil), // 12: authentication.CoordinateMessage (*CoordinateMessage)(nil), // 12: authentication.CoordinateMessage
(*RefreshPhoneRelayResponse)(nil), // 13: authentication.RefreshPhoneRelayResponse (*RefreshPhoneRelayResponse)(nil), // 13: authentication.RefreshPhoneRelayResponse
(*WebEncryptionKeyResponse)(nil), // 14: authentication.WebEncryptionKeyResponse (*WebEncryptionKeyResponse)(nil), // 14: authentication.WebEncryptionKeyResponse
(*ECDSAKeys)(nil), // 15: authentication.ECDSAKeys (*ErrorResponse)(nil), // 15: authentication.ErrorResponse
(*CurrentDeviceData)(nil), // 16: authentication.CurrentDeviceData (*ECDSAKeys)(nil), // 16: authentication.ECDSAKeys
(*KeyData)(nil), // 17: authentication.KeyData (*CurrentDeviceData)(nil), // 17: authentication.CurrentDeviceData
(*WebAuthKey)(nil), // 18: authentication.WebAuthKey (*KeyData)(nil), // 18: authentication.KeyData
(*URLData)(nil), // 19: authentication.URLData (*WebAuthKey)(nil), // 19: authentication.WebAuthKey
(*TokenData)(nil), // 20: authentication.TokenData (*URLData)(nil), // 20: authentication.URLData
(*PairedData)(nil), // 21: authentication.PairedData (*TokenData)(nil), // 21: authentication.TokenData
(*RevokePairData)(nil), // 22: authentication.RevokePairData (*PairedData)(nil), // 22: authentication.PairedData
(*RegisterRefreshRequest_NestedEmptyArr)(nil), // 23: authentication.RegisterRefreshRequest.NestedEmptyArr (*RevokePairData)(nil), // 23: authentication.RevokePairData
(*RegisterRefreshResponse_AuthKeyData)(nil), // 24: authentication.RegisterRefreshResponse.AuthKeyData (*RegisterRefreshRequest_NestedEmptyArr)(nil), // 24: authentication.RegisterRefreshRequest.NestedEmptyArr
(*RegisterPhoneRelayResponse_AuthKeyData)(nil), // 25: authentication.RegisterPhoneRelayResponse.AuthKeyData (*RegisterRefreshResponse_AuthKeyData)(nil), // 25: authentication.RegisterRefreshResponse.AuthKeyData
(*EmptyArr)(nil), // 26: util.EmptyArr (*RegisterPhoneRelayResponse_AuthKeyData)(nil), // 26: authentication.RegisterPhoneRelayResponse.AuthKeyData
(*ErrorResponse_ErrorClass)(nil), // 27: authentication.ErrorResponse.ErrorClass
(*EmptyArr)(nil), // 28: util.EmptyArr
} }
var file_authentication_proto_depIdxs = []int32{ var file_authentication_proto_depIdxs = []int32{
0, // 0: authentication.BrowserDetails.browserType:type_name -> authentication.BrowserType 0, // 0: authentication.BrowserDetails.browserType:type_name -> authentication.BrowserType
1, // 1: authentication.BrowserDetails.deviceType:type_name -> authentication.DeviceType 1, // 1: authentication.BrowserDetails.deviceType:type_name -> authentication.DeviceType
6, // 2: authentication.AuthenticationContainer.authMessage:type_name -> authentication.AuthMessage 6, // 2: authentication.AuthenticationContainer.authMessage:type_name -> authentication.AuthMessage
2, // 3: authentication.AuthenticationContainer.browserDetails:type_name -> authentication.BrowserDetails 2, // 3: authentication.AuthenticationContainer.browserDetails:type_name -> authentication.BrowserDetails
17, // 4: authentication.AuthenticationContainer.keyData:type_name -> authentication.KeyData 18, // 4: authentication.AuthenticationContainer.keyData:type_name -> authentication.KeyData
16, // 5: authentication.AuthenticationContainer.deviceData:type_name -> authentication.CurrentDeviceData 17, // 5: authentication.AuthenticationContainer.deviceData:type_name -> authentication.CurrentDeviceData
4, // 6: authentication.AuthMessage.configVersion:type_name -> authentication.ConfigVersion 4, // 6: authentication.AuthMessage.configVersion:type_name -> authentication.ConfigVersion
6, // 7: authentication.RevokeRelayPairingRequest.authMessage:type_name -> authentication.AuthMessage 6, // 7: authentication.RevokeRelayPairingRequest.authMessage:type_name -> authentication.AuthMessage
3, // 8: authentication.RevokeRelayPairingRequest.browser:type_name -> authentication.Device 3, // 8: authentication.RevokeRelayPairingRequest.browser:type_name -> authentication.Device
6, // 9: authentication.RegisterRefreshRequest.messageAuth:type_name -> authentication.AuthMessage 6, // 9: authentication.RegisterRefreshRequest.messageAuth:type_name -> authentication.AuthMessage
3, // 10: authentication.RegisterRefreshRequest.currBrowserDevice:type_name -> authentication.Device 3, // 10: authentication.RegisterRefreshRequest.currBrowserDevice:type_name -> authentication.Device
23, // 11: authentication.RegisterRefreshRequest.emptyRefreshArr:type_name -> authentication.RegisterRefreshRequest.NestedEmptyArr 24, // 11: authentication.RegisterRefreshRequest.emptyRefreshArr:type_name -> authentication.RegisterRefreshRequest.NestedEmptyArr
24, // 12: authentication.RegisterRefreshResponse.tokenData:type_name -> authentication.RegisterRefreshResponse.AuthKeyData 25, // 12: authentication.RegisterRefreshResponse.tokenData:type_name -> authentication.RegisterRefreshResponse.AuthKeyData
12, // 13: authentication.RegisterPhoneRelayResponse.coordinates:type_name -> authentication.CoordinateMessage 12, // 13: authentication.RegisterPhoneRelayResponse.coordinates:type_name -> authentication.CoordinateMessage
3, // 14: authentication.RegisterPhoneRelayResponse.browser:type_name -> authentication.Device 3, // 14: authentication.RegisterPhoneRelayResponse.browser:type_name -> authentication.Device
25, // 15: authentication.RegisterPhoneRelayResponse.authKeyData:type_name -> authentication.RegisterPhoneRelayResponse.AuthKeyData 26, // 15: authentication.RegisterPhoneRelayResponse.authKeyData:type_name -> authentication.RegisterPhoneRelayResponse.AuthKeyData
12, // 16: authentication.RefreshPhoneRelayResponse.coordinates:type_name -> authentication.CoordinateMessage 12, // 16: authentication.RefreshPhoneRelayResponse.coordinates:type_name -> authentication.CoordinateMessage
12, // 17: authentication.WebEncryptionKeyResponse.coordinates:type_name -> authentication.CoordinateMessage 12, // 17: authentication.WebEncryptionKeyResponse.coordinates:type_name -> authentication.CoordinateMessage
3, // 18: authentication.CurrentDeviceData.browser:type_name -> authentication.Device 27, // 18: authentication.ErrorResponse.class:type_name -> authentication.ErrorResponse.ErrorClass
3, // 19: authentication.KeyData.mobile:type_name -> authentication.Device 3, // 19: authentication.CurrentDeviceData.browser:type_name -> authentication.Device
15, // 20: authentication.KeyData.ecdsaKeys:type_name -> authentication.ECDSAKeys 3, // 20: authentication.KeyData.mobile:type_name -> authentication.Device
18, // 21: authentication.KeyData.webAuthKeyData:type_name -> authentication.WebAuthKey 16, // 21: authentication.KeyData.ecdsaKeys:type_name -> authentication.ECDSAKeys
3, // 22: authentication.KeyData.browser:type_name -> authentication.Device 19, // 22: authentication.KeyData.webAuthKeyData:type_name -> authentication.WebAuthKey
3, // 23: authentication.PairedData.mobile:type_name -> authentication.Device 3, // 23: authentication.KeyData.browser:type_name -> authentication.Device
20, // 24: authentication.PairedData.tokenData:type_name -> authentication.TokenData 3, // 24: authentication.PairedData.mobile:type_name -> authentication.Device
3, // 25: authentication.PairedData.browser:type_name -> authentication.Device 21, // 25: authentication.PairedData.tokenData:type_name -> authentication.TokenData
3, // 26: authentication.RevokePairData.revokedDevice:type_name -> authentication.Device 3, // 26: authentication.PairedData.browser:type_name -> authentication.Device
26, // 27: authentication.RegisterRefreshRequest.NestedEmptyArr.emptyArr:type_name -> util.EmptyArr 3, // 27: authentication.RevokePairData.revokedDevice:type_name -> authentication.Device
28, // [28:28] is the sub-list for method output_type 28, // 28: authentication.RegisterRefreshRequest.NestedEmptyArr.emptyArr:type_name -> util.EmptyArr
28, // [28:28] is the sub-list for method input_type 29, // [29:29] is the sub-list for method output_type
28, // [28:28] is the sub-list for extension type_name 29, // [29:29] is the sub-list for method input_type
28, // [28:28] is the sub-list for extension extendee 29, // [29:29] is the sub-list for extension type_name
0, // [0:28] is the sub-list for field type_name 29, // [29:29] is the sub-list for extension extendee
0, // [0:29] is the sub-list for field type_name
} }
func init() { file_authentication_proto_init() } func init() { file_authentication_proto_init() }
@ -1859,7 +1972,7 @@ func file_authentication_proto_init() {
} }
} }
file_authentication_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { file_authentication_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ECDSAKeys); i { switch v := v.(*ErrorResponse); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -1871,7 +1984,7 @@ func file_authentication_proto_init() {
} }
} }
file_authentication_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { file_authentication_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CurrentDeviceData); i { switch v := v.(*ECDSAKeys); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -1883,7 +1996,7 @@ func file_authentication_proto_init() {
} }
} }
file_authentication_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { file_authentication_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*KeyData); i { switch v := v.(*CurrentDeviceData); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -1895,7 +2008,7 @@ func file_authentication_proto_init() {
} }
} }
file_authentication_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { file_authentication_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*WebAuthKey); i { switch v := v.(*KeyData); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -1907,7 +2020,7 @@ func file_authentication_proto_init() {
} }
} }
file_authentication_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { file_authentication_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*URLData); i { switch v := v.(*WebAuthKey); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -1919,7 +2032,7 @@ func file_authentication_proto_init() {
} }
} }
file_authentication_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { file_authentication_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*TokenData); i { switch v := v.(*URLData); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -1931,7 +2044,7 @@ func file_authentication_proto_init() {
} }
} }
file_authentication_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { file_authentication_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*PairedData); i { switch v := v.(*TokenData); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -1943,7 +2056,7 @@ func file_authentication_proto_init() {
} }
} }
file_authentication_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { file_authentication_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RevokePairData); i { switch v := v.(*PairedData); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -1955,7 +2068,7 @@ func file_authentication_proto_init() {
} }
} }
file_authentication_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { file_authentication_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RegisterRefreshRequest_NestedEmptyArr); i { switch v := v.(*RevokePairData); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -1967,7 +2080,7 @@ func file_authentication_proto_init() {
} }
} }
file_authentication_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { file_authentication_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RegisterRefreshResponse_AuthKeyData); i { switch v := v.(*RegisterRefreshRequest_NestedEmptyArr); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -1979,6 +2092,18 @@ func file_authentication_proto_init() {
} }
} }
file_authentication_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { file_authentication_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RegisterRefreshResponse_AuthKeyData); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_authentication_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RegisterPhoneRelayResponse_AuthKeyData); i { switch v := v.(*RegisterPhoneRelayResponse_AuthKeyData); i {
case 0: case 0:
return &v.state return &v.state
@ -1990,6 +2115,18 @@ func file_authentication_proto_init() {
return nil return nil
} }
} }
file_authentication_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ErrorResponse_ErrorClass); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
} }
file_authentication_proto_msgTypes[3].OneofWrappers = []interface{}{ file_authentication_proto_msgTypes[3].OneofWrappers = []interface{}{
(*AuthenticationContainer_KeyData)(nil), (*AuthenticationContainer_KeyData)(nil),
@ -2002,7 +2139,7 @@ func file_authentication_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_authentication_proto_rawDesc, RawDescriptor: file_authentication_proto_rawDesc,
NumEnums: 2, NumEnums: 2,
NumMessages: 24, NumMessages: 26,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },

Binary file not shown.

View file

@ -121,6 +121,17 @@ message WebEncryptionKeyResponse {
bytes key = 2; bytes key = 2;
} }
message ErrorResponse {
int64 type = 1; // 5?
string message = 2;
repeated ErrorClass class = 3;
message ErrorClass {
string class = 1;
// 2: {1: 1}
}
}
message ECDSAKeys { message ECDSAKeys {
int64 field1 = 1; // idk? int64 field1 = 1; // idk?
bytes encryptedKeys = 2; bytes encryptedKeys = 2;

View file

@ -228,7 +228,7 @@ const (
SendMessageResponse_SUCCESS SendMessageResponse_Status = 1 SendMessageResponse_SUCCESS SendMessageResponse_Status = 1
SendMessageResponse_FAILURE_2 SendMessageResponse_Status = 2 SendMessageResponse_FAILURE_2 SendMessageResponse_Status = 2
SendMessageResponse_FAILURE_3 SendMessageResponse_Status = 3 SendMessageResponse_FAILURE_3 SendMessageResponse_Status = 3
SendMessageResponse_FAILURE_4 SendMessageResponse_Status = 4 SendMessageResponse_FAILURE_4 SendMessageResponse_Status = 4 // not default sms app?
) )
// Enum value maps for SendMessageResponse_Status. // Enum value maps for SendMessageResponse_Status.

View file

@ -2,14 +2,18 @@ package libgm
import ( import (
"bytes" "bytes"
"context"
"encoding/base64"
"fmt" "fmt"
"io" "io"
"mime" "mime"
"net/http" "net/http"
"github.com/rs/zerolog"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
"go.mau.fi/mautrix-gmessages/libgm/events" "go.mau.fi/mautrix-gmessages/libgm/events"
"go.mau.fi/mautrix-gmessages/libgm/gmproto"
"go.mau.fi/mautrix-gmessages/libgm/pblite" "go.mau.fi/mautrix-gmessages/libgm/pblite"
"go.mau.fi/mautrix-gmessages/libgm/util" "go.mau.fi/mautrix-gmessages/libgm/util"
) )
@ -31,7 +35,8 @@ func (c *Client) makeProtobufHTTPRequest(url string, data proto.Message, content
if err != nil { if err != nil {
return nil, err return nil, err
} }
req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(body)) ctx := c.Logger.WithContext(context.TODO())
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -43,34 +48,54 @@ func (c *Client) makeProtobufHTTPRequest(url string, data proto.Message, content
return res, nil return res, nil
} }
func decodeProtoResp(body []byte, contentType string, into proto.Message) error {
contentType, _, err := mime.ParseMediaType(contentType)
if err != nil {
return fmt.Errorf("failed to parse content-type: %w", err)
}
switch contentType {
case ContentTypeProtobuf:
return proto.Unmarshal(body, into)
case ContentTypePBLite:
return pblite.Unmarshal(body, into)
default:
return fmt.Errorf("unknown content type %s in response", contentType)
}
}
func typedHTTPResponse[T proto.Message](resp *http.Response, err error) (parsed T, retErr error) { func typedHTTPResponse[T proto.Message](resp *http.Response, err error) (parsed T, retErr error) {
if err != nil { if err != nil {
retErr = err retErr = err
return return
} }
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
retErr = events.HTTPError{Resp: resp}
return
}
body, err := io.ReadAll(resp.Body) body, err := io.ReadAll(resp.Body)
if err != nil { if err != nil {
retErr = fmt.Errorf("failed to read response body: %w", err) retErr = fmt.Errorf("failed to read response body: %w", err)
return return
} }
contentType, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) if resp.StatusCode < 200 || resp.StatusCode >= 300 {
if err != nil { logEvt := zerolog.Ctx(resp.Request.Context()).Debug().
retErr = fmt.Errorf("failed to parse content-type: %w", err) Int("status_code", resp.StatusCode).
Str("url", resp.Request.URL.String()).
Str("response_body", base64.StdEncoding.EncodeToString(body))
httpErr := events.HTTPError{Resp: resp, Body: body}
retErr = httpErr
var errorResp gmproto.ErrorResponse
errErr := decodeProtoResp(body, resp.Header.Get("Content-Type"), &errorResp)
if errErr == nil && errorResp.Message != "" {
logEvt = logEvt.Any("response_proto_err", &errorResp)
retErr = events.RequestError{
HTTP: &httpErr,
Data: &errorResp,
}
} else {
logEvt = logEvt.AnErr("proto_parse_err", errErr)
}
logEvt.Msg("HTTP request to Google Messages failed")
return return
} }
parsed = parsed.ProtoReflect().New().Interface().(T) parsed = parsed.ProtoReflect().New().Interface().(T)
switch contentType { retErr = decodeProtoResp(body, resp.Header.Get("Content-Type"), parsed)
case ContentTypeProtobuf:
retErr = proto.Unmarshal(body, parsed)
case ContentTypePBLite:
retErr = pblite.Unmarshal(body, parsed)
default:
retErr = fmt.Errorf("unknown content type %s in response", contentType)
}
return return
} }

View file

@ -23,7 +23,7 @@ import (
const phoneNotRespondingTimeout = 30 * time.Second const phoneNotRespondingTimeout = 30 * time.Second
func (c *Client) doDittoPinger(log *zerolog.Logger, dittoPing chan struct{}, stopPinger chan struct{}) { func (c *Client) doDittoPinger(log *zerolog.Logger, dittoPing <-chan struct{}, stopPinger <-chan struct{}) {
notResponding := false notResponding := false
exit := false exit := false
onRespond := func() { onRespond := func() {
@ -37,6 +37,9 @@ func (c *Client) doDittoPinger(log *zerolog.Logger, dittoPing chan struct{}, sto
pingChan, err := c.NotifyDittoActivity() pingChan, err := c.NotifyDittoActivity()
if err != nil { if err != nil {
log.Err(err).Msg("Error notifying ditto activity") log.Err(err).Msg("Error notifying ditto activity")
c.triggerEvent(&events.PingFailed{
Error: fmt.Errorf("failed to notify ditto activity: %w", err),
})
return return
} }
select { select {
@ -73,6 +76,12 @@ func (c *Client) doDittoPinger(log *zerolog.Logger, dittoPing chan struct{}, sto
} }
} }
func tryReadBody(resp io.ReadCloser) []byte {
data, _ := io.ReadAll(resp)
_ = resp.Close()
return data
}
func (c *Client) doLongPoll(loggedIn bool) { func (c *Client) doLongPoll(loggedIn bool) {
c.listenID++ c.listenID++
listenID := c.listenID listenID := c.listenID
@ -123,14 +132,20 @@ func (c *Client) doLongPoll(loggedIn bool) {
continue continue
} }
if resp.StatusCode == http.StatusUnauthorized || resp.StatusCode == http.StatusForbidden { if resp.StatusCode == http.StatusUnauthorized || resp.StatusCode == http.StatusForbidden {
log.Error().Int("status_code", resp.StatusCode).Msg("Error making listen request") body := tryReadBody(resp.Body)
log.Error().
Int("status_code", resp.StatusCode).
Bytes("resp_body", body).
Msg("Error making listen request")
if loggedIn { if loggedIn {
c.triggerEvent(&events.ListenFatalError{Error: events.HTTPError{Action: "polling", Resp: resp}}) c.triggerEvent(&events.ListenFatalError{Error: events.HTTPError{Action: "polling", Resp: resp, Body: body}})
} }
return return
} else if resp.StatusCode >= 400 { } else if resp.StatusCode >= 400 {
if loggedIn { if loggedIn {
c.triggerEvent(&events.ListenTemporaryError{Error: events.HTTPError{Action: "polling", Resp: resp}}) c.triggerEvent(&events.ListenTemporaryError{Error: events.HTTPError{Action: "polling", Resp: resp, Body: tryReadBody(resp.Body)}})
} else {
_ = resp.Body.Close()
} }
errorCount++ errorCount++
sleepSeconds := (errorCount + 1) * 5 sleepSeconds := (errorCount + 1) * 5

40
user.go
View file

@ -471,13 +471,23 @@ func (user *User) Connect() bool {
err := user.Client.Connect() err := user.Client.Connect()
if err != nil { if err != nil {
user.zlog.Err(err).Msg("Error connecting to Google Messages") user.zlog.Err(err).Msg("Error connecting to Google Messages")
user.BridgeState.Send(status.BridgeState{ if errors.Is(err, events.ErrRequestedEntityNotFound) {
StateEvent: status.StateUnknownError, go user.Logout(status.BridgeState{
Error: GMConnectionFailed, StateEvent: status.StateBadCredentials,
Info: map[string]interface{}{ Error: GMUnpaired,
"go_error": err.Error(), Info: map[string]any{
}, "go_error": err.Error(),
}) },
}, false)
} else {
user.BridgeState.Send(status.BridgeState{
StateEvent: status.StateUnknownError,
Error: GMConnectionFailed,
Info: map[string]interface{}{
"go_error": err.Error(),
},
})
}
return false return false
} }
return true return true
@ -569,6 +579,22 @@ func (user *User) syncHandleEvent(event any) {
case *events.PhoneRespondingAgain: case *events.PhoneRespondingAgain:
user.phoneResponding = true user.phoneResponding = true
user.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnected}) user.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnected})
case *events.PingFailed:
if errors.Is(v.Error, events.ErrRequestedEntityNotFound) {
go user.Logout(status.BridgeState{
StateEvent: status.StateBadCredentials,
Error: GMUnpaired,
Info: map[string]any{
"go_error": v.Error.Error(),
},
}, false)
} else {
user.BridgeState.Send(status.BridgeState{
StateEvent: status.StateUnknownError,
Error: GMPingFailed,
Info: map[string]any{"go_error": v.Error.Error()},
})
}
case *events.PairSuccessful: case *events.PairSuccessful:
user.Session = user.Client.AuthData user.Session = user.Client.AuthData
if user.PhoneID != "" && user.PhoneID != v.GetMobile().GetSourceID() { if user.PhoneID != "" && user.PhoneID != v.GetMobile().GetSourceID() {