Add initial Google Messages library

This commit is contained in:
zero 2023-06-30 12:54:08 +03:00 committed by Tulir Asokan
parent a8bdcb2750
commit 02ef5ab82c
72 changed files with 12059 additions and 0 deletions

637
libgm/binary/client.pb.go Normal file
View file

@ -0,0 +1,637 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.30.0
// protoc v3.21.12
// source: client.proto
package binary
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type SendMessage struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
PairedDevice *Device `protobuf:"bytes,1,opt,name=pairedDevice,proto3" json:"pairedDevice,omitempty"`
MessageData *MessageData `protobuf:"bytes,2,opt,name=messageData,proto3" json:"messageData,omitempty"`
AuthData *AuthMessage `protobuf:"bytes,3,opt,name=authData,proto3" json:"authData,omitempty"`
Ttl int64 `protobuf:"varint,5,opt,name=ttl,proto3" json:"ttl,omitempty"`
EmptyArr *EmptyArr `protobuf:"bytes,9,opt,name=emptyArr,proto3" json:"emptyArr,omitempty"`
}
func (x *SendMessage) Reset() {
*x = SendMessage{}
if protoimpl.UnsafeEnabled {
mi := &file_client_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SendMessage) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SendMessage) ProtoMessage() {}
func (x *SendMessage) ProtoReflect() protoreflect.Message {
mi := &file_client_proto_msgTypes[0]
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 SendMessage.ProtoReflect.Descriptor instead.
func (*SendMessage) Descriptor() ([]byte, []int) {
return file_client_proto_rawDescGZIP(), []int{0}
}
func (x *SendMessage) GetPairedDevice() *Device {
if x != nil {
return x.PairedDevice
}
return nil
}
func (x *SendMessage) GetMessageData() *MessageData {
if x != nil {
return x.MessageData
}
return nil
}
func (x *SendMessage) GetAuthData() *AuthMessage {
if x != nil {
return x.AuthData
}
return nil
}
func (x *SendMessage) GetTtl() int64 {
if x != nil {
return x.Ttl
}
return 0
}
func (x *SendMessage) GetEmptyArr() *EmptyArr {
if x != nil {
return x.EmptyArr
}
return nil
}
type AckMessagePayload struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
AuthData *AuthMessage `protobuf:"bytes,1,opt,name=authData,proto3" json:"authData,omitempty"`
EmptyArr *EmptyArr `protobuf:"bytes,2,opt,name=emptyArr,proto3" json:"emptyArr,omitempty"`
NoClue []byte `protobuf:"bytes,3,opt,name=noClue,proto3" json:"noClue,omitempty"`
}
func (x *AckMessagePayload) Reset() {
*x = AckMessagePayload{}
if protoimpl.UnsafeEnabled {
mi := &file_client_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AckMessagePayload) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AckMessagePayload) ProtoMessage() {}
func (x *AckMessagePayload) ProtoReflect() protoreflect.Message {
mi := &file_client_proto_msgTypes[1]
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 AckMessagePayload.ProtoReflect.Descriptor instead.
func (*AckMessagePayload) Descriptor() ([]byte, []int) {
return file_client_proto_rawDescGZIP(), []int{1}
}
func (x *AckMessagePayload) GetAuthData() *AuthMessage {
if x != nil {
return x.AuthData
}
return nil
}
func (x *AckMessagePayload) GetEmptyArr() *EmptyArr {
if x != nil {
return x.EmptyArr
}
return nil
}
func (x *AckMessagePayload) GetNoClue() []byte {
if x != nil {
return x.NoClue
}
return nil
}
type AckMessageData struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"`
Device *Device `protobuf:"bytes,2,opt,name=device,proto3" json:"device,omitempty"`
}
func (x *AckMessageData) Reset() {
*x = AckMessageData{}
if protoimpl.UnsafeEnabled {
mi := &file_client_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *AckMessageData) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AckMessageData) ProtoMessage() {}
func (x *AckMessageData) ProtoReflect() protoreflect.Message {
mi := &file_client_proto_msgTypes[2]
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 AckMessageData.ProtoReflect.Descriptor instead.
func (*AckMessageData) Descriptor() ([]byte, []int) {
return file_client_proto_rawDescGZIP(), []int{2}
}
func (x *AckMessageData) GetRequestId() string {
if x != nil {
return x.RequestId
}
return ""
}
func (x *AckMessageData) GetDevice() *Device {
if x != nil {
return x.Device
}
return nil
}
type ImageMetaData struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ImageId string `protobuf:"bytes,1,opt,name=imageId,proto3" json:"imageId,omitempty"`
Encrypted bool `protobuf:"varint,2,opt,name=encrypted,proto3" json:"encrypted,omitempty"`
}
func (x *ImageMetaData) Reset() {
*x = ImageMetaData{}
if protoimpl.UnsafeEnabled {
mi := &file_client_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ImageMetaData) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ImageMetaData) ProtoMessage() {}
func (x *ImageMetaData) ProtoReflect() protoreflect.Message {
mi := &file_client_proto_msgTypes[3]
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 ImageMetaData.ProtoReflect.Descriptor instead.
func (*ImageMetaData) Descriptor() ([]byte, []int) {
return file_client_proto_rawDescGZIP(), []int{3}
}
func (x *ImageMetaData) GetImageId() string {
if x != nil {
return x.ImageId
}
return ""
}
func (x *ImageMetaData) GetEncrypted() bool {
if x != nil {
return x.Encrypted
}
return false
}
type UploadImagePayload struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
MetaData *ImageMetaData `protobuf:"bytes,1,opt,name=metaData,proto3" json:"metaData,omitempty"`
AuthData *AuthMessageBytes `protobuf:"bytes,2,opt,name=authData,proto3" json:"authData,omitempty"`
}
func (x *UploadImagePayload) Reset() {
*x = UploadImagePayload{}
if protoimpl.UnsafeEnabled {
mi := &file_client_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *UploadImagePayload) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*UploadImagePayload) ProtoMessage() {}
func (x *UploadImagePayload) ProtoReflect() protoreflect.Message {
mi := &file_client_proto_msgTypes[4]
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 UploadImagePayload.ProtoReflect.Descriptor instead.
func (*UploadImagePayload) Descriptor() ([]byte, []int) {
return file_client_proto_rawDescGZIP(), []int{4}
}
func (x *UploadImagePayload) GetMetaData() *ImageMetaData {
if x != nil {
return x.MetaData
}
return nil
}
func (x *UploadImagePayload) GetAuthData() *AuthMessageBytes {
if x != nil {
return x.AuthData
}
return nil
}
type BugleBackendService struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Data *BugleCode `protobuf:"bytes,6,opt,name=data,proto3" json:"data,omitempty"`
}
func (x *BugleBackendService) Reset() {
*x = BugleBackendService{}
if protoimpl.UnsafeEnabled {
mi := &file_client_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *BugleBackendService) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BugleBackendService) ProtoMessage() {}
func (x *BugleBackendService) ProtoReflect() protoreflect.Message {
mi := &file_client_proto_msgTypes[5]
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 BugleBackendService.ProtoReflect.Descriptor instead.
func (*BugleBackendService) Descriptor() ([]byte, []int) {
return file_client_proto_rawDescGZIP(), []int{5}
}
func (x *BugleBackendService) GetData() *BugleCode {
if x != nil {
return x.Data
}
return nil
}
type BugleCode struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Type int64 `protobuf:"varint,2,opt,name=type,proto3" json:"type,omitempty"`
}
func (x *BugleCode) Reset() {
*x = BugleCode{}
if protoimpl.UnsafeEnabled {
mi := &file_client_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *BugleCode) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BugleCode) ProtoMessage() {}
func (x *BugleCode) ProtoReflect() protoreflect.Message {
mi := &file_client_proto_msgTypes[6]
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 BugleCode.ProtoReflect.Descriptor instead.
func (*BugleCode) Descriptor() ([]byte, []int) {
return file_client_proto_rawDescGZIP(), []int{6}
}
func (x *BugleCode) GetType() int64 {
if x != nil {
return x.Type
}
return 0
}
var File_client_proto protoreflect.FileDescriptor
var file_client_proto_rawDesc = []byte{
0x0a, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06,
0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x1a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf1, 0x01, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x4d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x34, 0x0a, 0x0c, 0x70, 0x61, 0x69, 0x72, 0x65, 0x64,
0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x0c,
0x70, 0x61, 0x69, 0x72, 0x65, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x37, 0x0a, 0x0b,
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x4d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, 0x0b, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x31, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x68, 0x44, 0x61, 0x74,
0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x73, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x08,
0x61, 0x75, 0x74, 0x68, 0x44, 0x61, 0x74, 0x61, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x74, 0x6c, 0x18,
0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x74, 0x74, 0x6c, 0x12, 0x2e, 0x0a, 0x08, 0x65, 0x6d,
0x70, 0x74, 0x79, 0x41, 0x72, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x41, 0x72, 0x72,
0x52, 0x08, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x41, 0x72, 0x72, 0x22, 0x8e, 0x01, 0x0a, 0x11, 0x41,
0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64,
0x12, 0x31, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x68, 0x44, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x41, 0x75,
0x74, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x08, 0x61, 0x75, 0x74, 0x68, 0x44,
0x61, 0x74, 0x61, 0x12, 0x2e, 0x0a, 0x08, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x41, 0x72, 0x72, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73,
0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x41, 0x72, 0x72, 0x52, 0x08, 0x65, 0x6d, 0x70, 0x74, 0x79,
0x41, 0x72, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x6f, 0x43, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x06, 0x6e, 0x6f, 0x43, 0x6c, 0x75, 0x65, 0x22, 0x59, 0x0a, 0x0e, 0x41,
0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1d, 0x0a,
0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x06,
0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x06,
0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x22, 0x47, 0x0a, 0x0d, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x4d,
0x65, 0x74, 0x61, 0x44, 0x61, 0x74, 0x61, 0x12, 0x18, 0x0a, 0x07, 0x69, 0x6d, 0x61, 0x67, 0x65,
0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x49,
0x64, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x18, 0x02,
0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x22,
0x7f, 0x0a, 0x12, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x50, 0x61,
0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x44, 0x61, 0x74,
0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
0x2e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x44, 0x61, 0x74, 0x61, 0x52, 0x08,
0x6d, 0x65, 0x74, 0x61, 0x44, 0x61, 0x74, 0x61, 0x12, 0x36, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x68,
0x44, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x08, 0x61, 0x75, 0x74, 0x68, 0x44, 0x61, 0x74, 0x61,
0x22, 0x3c, 0x0a, 0x13, 0x42, 0x75, 0x67, 0x6c, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64,
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x25, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18,
0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x42,
0x75, 0x67, 0x6c, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x1f,
0x0a, 0x09, 0x42, 0x75, 0x67, 0x6c, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74,
0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x42,
0x0e, 0x5a, 0x0c, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_client_proto_rawDescOnce sync.Once
file_client_proto_rawDescData = file_client_proto_rawDesc
)
func file_client_proto_rawDescGZIP() []byte {
file_client_proto_rawDescOnce.Do(func() {
file_client_proto_rawDescData = protoimpl.X.CompressGZIP(file_client_proto_rawDescData)
})
return file_client_proto_rawDescData
}
var file_client_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_client_proto_goTypes = []interface{}{
(*SendMessage)(nil), // 0: client.SendMessage
(*AckMessagePayload)(nil), // 1: client.AckMessagePayload
(*AckMessageData)(nil), // 2: client.AckMessageData
(*ImageMetaData)(nil), // 3: client.ImageMetaData
(*UploadImagePayload)(nil), // 4: client.UploadImagePayload
(*BugleBackendService)(nil), // 5: client.BugleBackendService
(*BugleCode)(nil), // 6: client.BugleCode
(*Device)(nil), // 7: messages.Device
(*MessageData)(nil), // 8: messages.MessageData
(*AuthMessage)(nil), // 9: messages.AuthMessage
(*EmptyArr)(nil), // 10: messages.EmptyArr
(*AuthMessageBytes)(nil), // 11: messages.AuthMessageBytes
}
var file_client_proto_depIdxs = []int32{
7, // 0: client.SendMessage.pairedDevice:type_name -> messages.Device
8, // 1: client.SendMessage.messageData:type_name -> messages.MessageData
9, // 2: client.SendMessage.authData:type_name -> messages.AuthMessage
10, // 3: client.SendMessage.emptyArr:type_name -> messages.EmptyArr
9, // 4: client.AckMessagePayload.authData:type_name -> messages.AuthMessage
10, // 5: client.AckMessagePayload.emptyArr:type_name -> messages.EmptyArr
7, // 6: client.AckMessageData.device:type_name -> messages.Device
3, // 7: client.UploadImagePayload.metaData:type_name -> client.ImageMetaData
11, // 8: client.UploadImagePayload.authData:type_name -> messages.AuthMessageBytes
6, // 9: client.BugleBackendService.data:type_name -> client.BugleCode
10, // [10:10] is the sub-list for method output_type
10, // [10:10] is the sub-list for method input_type
10, // [10:10] is the sub-list for extension type_name
10, // [10:10] is the sub-list for extension extendee
0, // [0:10] is the sub-list for field type_name
}
func init() { file_client_proto_init() }
func file_client_proto_init() {
if File_client_proto != nil {
return
}
file_messages_proto_init()
if !protoimpl.UnsafeEnabled {
file_client_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SendMessage); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_client_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AckMessagePayload); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_client_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AckMessageData); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_client_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ImageMetaData); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_client_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*UploadImagePayload); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_client_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*BugleBackendService); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_client_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*BugleCode); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_client_proto_rawDesc,
NumEnums: 0,
NumMessages: 7,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_client_proto_goTypes,
DependencyIndexes: file_client_proto_depIdxs,
MessageInfos: file_client_proto_msgTypes,
}.Build()
File_client_proto = out.File
file_client_proto_rawDesc = nil
file_client_proto_goTypes = nil
file_client_proto_depIdxs = nil
}

File diff suppressed because it is too large Load diff

424
libgm/binary/events.pb.go Normal file
View file

@ -0,0 +1,424 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.30.0
// protoc v3.21.12
// source: events.proto
package binary
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Event struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Types that are assignable to Event:
//
// *Event_ConversationEvent
// *Event_MessageEvent
// *Event_UserAlertEvent
Event isEvent_Event `protobuf_oneof:"event"`
}
func (x *Event) Reset() {
*x = Event{}
if protoimpl.UnsafeEnabled {
mi := &file_events_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Event) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Event) ProtoMessage() {}
func (x *Event) ProtoReflect() protoreflect.Message {
mi := &file_events_proto_msgTypes[0]
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 Event.ProtoReflect.Descriptor instead.
func (*Event) Descriptor() ([]byte, []int) {
return file_events_proto_rawDescGZIP(), []int{0}
}
func (m *Event) GetEvent() isEvent_Event {
if m != nil {
return m.Event
}
return nil
}
func (x *Event) GetConversationEvent() *ConversationEvent {
if x, ok := x.GetEvent().(*Event_ConversationEvent); ok {
return x.ConversationEvent
}
return nil
}
func (x *Event) GetMessageEvent() *MessageEvent {
if x, ok := x.GetEvent().(*Event_MessageEvent); ok {
return x.MessageEvent
}
return nil
}
func (x *Event) GetUserAlertEvent() *UserAlertEvent {
if x, ok := x.GetEvent().(*Event_UserAlertEvent); ok {
return x.UserAlertEvent
}
return nil
}
type isEvent_Event interface {
isEvent_Event()
}
type Event_ConversationEvent struct {
ConversationEvent *ConversationEvent `protobuf:"bytes,2,opt,name=conversationEvent,proto3,oneof"`
}
type Event_MessageEvent struct {
MessageEvent *MessageEvent `protobuf:"bytes,3,opt,name=messageEvent,proto3,oneof"`
}
type Event_UserAlertEvent struct {
UserAlertEvent *UserAlertEvent `protobuf:"bytes,6,opt,name=userAlertEvent,proto3,oneof"`
}
func (*Event_ConversationEvent) isEvent_Event() {}
func (*Event_MessageEvent) isEvent_Event() {}
func (*Event_UserAlertEvent) isEvent_Event() {}
type ConversationEvent struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Data *Conversation `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
}
func (x *ConversationEvent) Reset() {
*x = ConversationEvent{}
if protoimpl.UnsafeEnabled {
mi := &file_events_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ConversationEvent) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConversationEvent) ProtoMessage() {}
func (x *ConversationEvent) ProtoReflect() protoreflect.Message {
mi := &file_events_proto_msgTypes[1]
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 ConversationEvent.ProtoReflect.Descriptor instead.
func (*ConversationEvent) Descriptor() ([]byte, []int) {
return file_events_proto_rawDescGZIP(), []int{1}
}
func (x *ConversationEvent) GetData() *Conversation {
if x != nil {
return x.Data
}
return nil
}
type MessageEvent struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Data *Message `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
}
func (x *MessageEvent) Reset() {
*x = MessageEvent{}
if protoimpl.UnsafeEnabled {
mi := &file_events_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MessageEvent) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MessageEvent) ProtoMessage() {}
func (x *MessageEvent) ProtoReflect() protoreflect.Message {
mi := &file_events_proto_msgTypes[2]
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 MessageEvent.ProtoReflect.Descriptor instead.
func (*MessageEvent) Descriptor() ([]byte, []int) {
return file_events_proto_rawDescGZIP(), []int{2}
}
func (x *MessageEvent) GetData() *Message {
if x != nil {
return x.Data
}
return nil
}
type UserAlertEvent struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// 2 = BROWSER_ACTIVE (new session created in other browser)
//
// 1 = ?
//
// 8 = INACTIVE_LACK_OF_ACTIVITY
//
// 7 = INACTIVE_TIMEOUT
//
// 5|6 = BATTERY (tf?)
//
// 3|4 = DATA_CONNECTION (tf?)
//
// 10 = OBSERVER_REGISTERED (tf?)
AlertType int64 `protobuf:"varint,2,opt,name=alert_type,json=alertType,proto3" json:"alert_type,omitempty"`
}
func (x *UserAlertEvent) Reset() {
*x = UserAlertEvent{}
if protoimpl.UnsafeEnabled {
mi := &file_events_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *UserAlertEvent) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*UserAlertEvent) ProtoMessage() {}
func (x *UserAlertEvent) ProtoReflect() protoreflect.Message {
mi := &file_events_proto_msgTypes[3]
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 UserAlertEvent.ProtoReflect.Descriptor instead.
func (*UserAlertEvent) Descriptor() ([]byte, []int) {
return file_events_proto_rawDescGZIP(), []int{3}
}
func (x *UserAlertEvent) GetAlertType() int64 {
if x != nil {
return x.AlertType
}
return 0
}
var File_events_proto protoreflect.FileDescriptor
var file_events_proto_rawDesc = []byte{
0x0a, 0x0c, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06,
0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0x0e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x13, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd9, 0x01, 0x0a, 0x05,
0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x49, 0x0a, 0x11, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x19, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72,
0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x11, 0x63,
0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74,
0x12, 0x3a, 0x0a, 0x0c, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74,
0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e,
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0c,
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x40, 0x0a, 0x0e,
0x75, 0x73, 0x65, 0x72, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x06,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x55, 0x73,
0x65, 0x72, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0e,
0x75, 0x73, 0x65, 0x72, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x07,
0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x44, 0x0a, 0x11, 0x43, 0x6f, 0x6e, 0x76, 0x65,
0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2f, 0x0a, 0x04,
0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x6e,
0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65,
0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x3a, 0x0a,
0x0c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2a, 0x0a,
0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x6f,
0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73,
0x61, 0x67, 0x65, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x2f, 0x0a, 0x0e, 0x55, 0x73, 0x65,
0x72, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x61,
0x6c, 0x65, 0x72, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52,
0x09, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x42, 0x0e, 0x5a, 0x0c, 0x2e, 0x2e,
0x2f, 0x2e, 0x2e, 0x2f, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (
file_events_proto_rawDescOnce sync.Once
file_events_proto_rawDescData = file_events_proto_rawDesc
)
func file_events_proto_rawDescGZIP() []byte {
file_events_proto_rawDescOnce.Do(func() {
file_events_proto_rawDescData = protoimpl.X.CompressGZIP(file_events_proto_rawDescData)
})
return file_events_proto_rawDescData
}
var file_events_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_events_proto_goTypes = []interface{}{
(*Event)(nil), // 0: events.Event
(*ConversationEvent)(nil), // 1: events.ConversationEvent
(*MessageEvent)(nil), // 2: events.MessageEvent
(*UserAlertEvent)(nil), // 3: events.UserAlertEvent
(*Conversation)(nil), // 4: conversations.Conversation
(*Message)(nil), // 5: conversations.Message
}
var file_events_proto_depIdxs = []int32{
1, // 0: events.Event.conversationEvent:type_name -> events.ConversationEvent
2, // 1: events.Event.messageEvent:type_name -> events.MessageEvent
3, // 2: events.Event.userAlertEvent:type_name -> events.UserAlertEvent
4, // 3: events.ConversationEvent.data:type_name -> conversations.Conversation
5, // 4: events.MessageEvent.data:type_name -> conversations.Message
5, // [5:5] is the sub-list for method output_type
5, // [5:5] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
}
func init() { file_events_proto_init() }
func file_events_proto_init() {
if File_events_proto != nil {
return
}
file_settings_proto_init()
file_messages_proto_init()
file_conversations_proto_init()
if !protoimpl.UnsafeEnabled {
file_events_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Event); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_events_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ConversationEvent); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_events_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*MessageEvent); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_events_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*UserAlertEvent); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
file_events_proto_msgTypes[0].OneofWrappers = []interface{}{
(*Event_ConversationEvent)(nil),
(*Event_MessageEvent)(nil),
(*Event_UserAlertEvent)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_events_proto_rawDesc,
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_events_proto_goTypes,
DependencyIndexes: file_events_proto_depIdxs,
MessageInfos: file_events_proto_msgTypes,
}.Build()
File_events_proto = out.File
file_events_proto_rawDesc = nil
file_events_proto_goTypes = nil
file_events_proto_depIdxs = nil
}

318
libgm/binary/media.pb.go Normal file
View file

@ -0,0 +1,318 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.30.0
// protoc v3.21.12
// source: media.proto
package binary
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type StartMediaUploadPayload struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ImageType int64 `protobuf:"varint,1,opt,name=imageType,proto3" json:"imageType,omitempty"`
AuthData *AuthMessageBytes `protobuf:"bytes,2,opt,name=authData,proto3" json:"authData,omitempty"`
Mobile *Device `protobuf:"bytes,3,opt,name=mobile,proto3" json:"mobile,omitempty"`
}
func (x *StartMediaUploadPayload) Reset() {
*x = StartMediaUploadPayload{}
if protoimpl.UnsafeEnabled {
mi := &file_media_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *StartMediaUploadPayload) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*StartMediaUploadPayload) ProtoMessage() {}
func (x *StartMediaUploadPayload) ProtoReflect() protoreflect.Message {
mi := &file_media_proto_msgTypes[0]
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 StartMediaUploadPayload.ProtoReflect.Descriptor instead.
func (*StartMediaUploadPayload) Descriptor() ([]byte, []int) {
return file_media_proto_rawDescGZIP(), []int{0}
}
func (x *StartMediaUploadPayload) GetImageType() int64 {
if x != nil {
return x.ImageType
}
return 0
}
func (x *StartMediaUploadPayload) GetAuthData() *AuthMessageBytes {
if x != nil {
return x.AuthData
}
return nil
}
func (x *StartMediaUploadPayload) GetMobile() *Device {
if x != nil {
return x.Mobile
}
return nil
}
type UploadMediaResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Media *Media `protobuf:"bytes,1,opt,name=media,proto3" json:"media,omitempty"`
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
}
func (x *UploadMediaResponse) Reset() {
*x = UploadMediaResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_media_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *UploadMediaResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*UploadMediaResponse) ProtoMessage() {}
func (x *UploadMediaResponse) ProtoReflect() protoreflect.Message {
mi := &file_media_proto_msgTypes[1]
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 UploadMediaResponse.ProtoReflect.Descriptor instead.
func (*UploadMediaResponse) Descriptor() ([]byte, []int) {
return file_media_proto_rawDescGZIP(), []int{1}
}
func (x *UploadMediaResponse) GetMedia() *Media {
if x != nil {
return x.Media
}
return nil
}
func (x *UploadMediaResponse) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
type Media struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
MediaId string `protobuf:"bytes,1,opt,name=mediaId,proto3" json:"mediaId,omitempty"`
MediaNumber int64 `protobuf:"varint,2,opt,name=mediaNumber,proto3" json:"mediaNumber,omitempty"`
}
func (x *Media) Reset() {
*x = Media{}
if protoimpl.UnsafeEnabled {
mi := &file_media_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Media) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Media) ProtoMessage() {}
func (x *Media) ProtoReflect() protoreflect.Message {
mi := &file_media_proto_msgTypes[2]
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 Media.ProtoReflect.Descriptor instead.
func (*Media) Descriptor() ([]byte, []int) {
return file_media_proto_rawDescGZIP(), []int{2}
}
func (x *Media) GetMediaId() string {
if x != nil {
return x.MediaId
}
return ""
}
func (x *Media) GetMediaNumber() int64 {
if x != nil {
return x.MediaNumber
}
return 0
}
var File_media_proto protoreflect.FileDescriptor
var file_media_proto_rawDesc = []byte{
0x0a, 0x0b, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x6d,
0x65, 0x64, 0x69, 0x61, 0x1a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x22, 0x99, 0x01, 0x0a, 0x17, 0x53, 0x74, 0x61, 0x72, 0x74, 0x4d, 0x65,
0x64, 0x69, 0x61, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64,
0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20,
0x01, 0x28, 0x03, 0x52, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x36,
0x0a, 0x08, 0x61, 0x75, 0x74, 0x68, 0x44, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x1a, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x41, 0x75, 0x74, 0x68,
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x08, 0x61, 0x75,
0x74, 0x68, 0x44, 0x61, 0x74, 0x61, 0x12, 0x28, 0x0a, 0x06, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65,
0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
0x73, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x06, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65,
0x22, 0x53, 0x0a, 0x13, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x22, 0x0a, 0x05, 0x6d, 0x65, 0x64, 0x69, 0x61,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x2e, 0x4d,
0x65, 0x64, 0x69, 0x61, 0x52, 0x05, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x12, 0x18, 0x0a, 0x07, 0x6d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65,
0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x43, 0x0a, 0x05, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x12, 0x18,
0x0a, 0x07, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x07, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x65, 0x64, 0x69,
0x61, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6d,
0x65, 0x64, 0x69, 0x61, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x42, 0x0e, 0x5a, 0x0c, 0x2e, 0x2e,
0x2f, 0x2e, 0x2e, 0x2f, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (
file_media_proto_rawDescOnce sync.Once
file_media_proto_rawDescData = file_media_proto_rawDesc
)
func file_media_proto_rawDescGZIP() []byte {
file_media_proto_rawDescOnce.Do(func() {
file_media_proto_rawDescData = protoimpl.X.CompressGZIP(file_media_proto_rawDescData)
})
return file_media_proto_rawDescData
}
var file_media_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_media_proto_goTypes = []interface{}{
(*StartMediaUploadPayload)(nil), // 0: media.StartMediaUploadPayload
(*UploadMediaResponse)(nil), // 1: media.UploadMediaResponse
(*Media)(nil), // 2: media.Media
(*AuthMessageBytes)(nil), // 3: messages.AuthMessageBytes
(*Device)(nil), // 4: messages.Device
}
var file_media_proto_depIdxs = []int32{
3, // 0: media.StartMediaUploadPayload.authData:type_name -> messages.AuthMessageBytes
4, // 1: media.StartMediaUploadPayload.mobile:type_name -> messages.Device
2, // 2: media.UploadMediaResponse.media:type_name -> media.Media
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_media_proto_init() }
func file_media_proto_init() {
if File_media_proto != nil {
return
}
file_messages_proto_init()
if !protoimpl.UnsafeEnabled {
file_media_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*StartMediaUploadPayload); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_media_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*UploadMediaResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_media_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Media); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_media_proto_rawDesc,
NumEnums: 0,
NumMessages: 3,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_media_proto_goTypes,
DependencyIndexes: file_media_proto_depIdxs,
MessageInfos: file_media_proto_msgTypes,
}.Build()
File_media_proto = out.File
file_media_proto_rawDesc = nil
file_media_proto_goTypes = nil
file_media_proto_depIdxs = nil
}

1086
libgm/binary/messages.pb.go Normal file

File diff suppressed because it is too large Load diff

689
libgm/binary/pairing.pb.go Normal file
View file

@ -0,0 +1,689 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.30.0
// protoc v3.21.12
// source: pairing.proto
package binary
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type BrowserDetails struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
UserAgent string `protobuf:"bytes,1,opt,name=user_agent,json=userAgent,proto3" json:"user_agent,omitempty"`
SomeInt int32 `protobuf:"varint,2,opt,name=someInt,proto3" json:"someInt,omitempty"`
Os string `protobuf:"bytes,3,opt,name=os,proto3" json:"os,omitempty"`
SomeBool bool `protobuf:"varint,6,opt,name=someBool,proto3" json:"someBool,omitempty"`
}
func (x *BrowserDetails) Reset() {
*x = BrowserDetails{}
if protoimpl.UnsafeEnabled {
mi := &file_pairing_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *BrowserDetails) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BrowserDetails) ProtoMessage() {}
func (x *BrowserDetails) ProtoReflect() protoreflect.Message {
mi := &file_pairing_proto_msgTypes[0]
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 BrowserDetails.ProtoReflect.Descriptor instead.
func (*BrowserDetails) Descriptor() ([]byte, []int) {
return file_pairing_proto_rawDescGZIP(), []int{0}
}
func (x *BrowserDetails) GetUserAgent() string {
if x != nil {
return x.UserAgent
}
return ""
}
func (x *BrowserDetails) GetSomeInt() int32 {
if x != nil {
return x.SomeInt
}
return 0
}
func (x *BrowserDetails) GetOs() string {
if x != nil {
return x.Os
}
return ""
}
func (x *BrowserDetails) GetSomeBool() bool {
if x != nil {
return x.SomeBool
}
return false
}
type PhoneRelayBody struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Bugle string `protobuf:"bytes,3,opt,name=bugle,proto3" json:"bugle,omitempty"`
RpcKey []byte `protobuf:"bytes,6,opt,name=rpcKey,proto3" json:"rpcKey,omitempty"`
Date *Date `protobuf:"bytes,7,opt,name=date,proto3" json:"date,omitempty"`
}
func (x *PhoneRelayBody) Reset() {
*x = PhoneRelayBody{}
if protoimpl.UnsafeEnabled {
mi := &file_pairing_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *PhoneRelayBody) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PhoneRelayBody) ProtoMessage() {}
func (x *PhoneRelayBody) ProtoReflect() protoreflect.Message {
mi := &file_pairing_proto_msgTypes[1]
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 PhoneRelayBody.ProtoReflect.Descriptor instead.
func (*PhoneRelayBody) Descriptor() ([]byte, []int) {
return file_pairing_proto_rawDescGZIP(), []int{1}
}
func (x *PhoneRelayBody) GetId() string {
if x != nil {
return x.Id
}
return ""
}
func (x *PhoneRelayBody) GetBugle() string {
if x != nil {
return x.Bugle
}
return ""
}
func (x *PhoneRelayBody) GetRpcKey() []byte {
if x != nil {
return x.RpcKey
}
return nil
}
func (x *PhoneRelayBody) GetDate() *Date {
if x != nil {
return x.Date
}
return nil
}
type ECDSAKeys struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ProtoVersion int64 `protobuf:"varint,1,opt,name=protoVersion,proto3" json:"protoVersion,omitempty"` // idk?
EncryptedKeys []byte `protobuf:"bytes,2,opt,name=encryptedKeys,proto3" json:"encryptedKeys,omitempty"`
}
func (x *ECDSAKeys) Reset() {
*x = ECDSAKeys{}
if protoimpl.UnsafeEnabled {
mi := &file_pairing_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ECDSAKeys) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ECDSAKeys) ProtoMessage() {}
func (x *ECDSAKeys) ProtoReflect() protoreflect.Message {
mi := &file_pairing_proto_msgTypes[2]
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 ECDSAKeys.ProtoReflect.Descriptor instead.
func (*ECDSAKeys) Descriptor() ([]byte, []int) {
return file_pairing_proto_rawDescGZIP(), []int{2}
}
func (x *ECDSAKeys) GetProtoVersion() int64 {
if x != nil {
return x.ProtoVersion
}
return 0
}
func (x *ECDSAKeys) GetEncryptedKeys() []byte {
if x != nil {
return x.EncryptedKeys
}
return nil
}
type PairDeviceData struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Mobile *Device `protobuf:"bytes,1,opt,name=mobile,proto3" json:"mobile,omitempty"`
EcdsaKeys *ECDSAKeys `protobuf:"bytes,6,opt,name=ecdsaKeys,proto3" json:"ecdsaKeys,omitempty"`
WebAuthKeyData *WebAuthKey `protobuf:"bytes,2,opt,name=webAuthKeyData,proto3" json:"webAuthKeyData,omitempty"`
Browser *Device `protobuf:"bytes,3,opt,name=browser,proto3" json:"browser,omitempty"`
}
func (x *PairDeviceData) Reset() {
*x = PairDeviceData{}
if protoimpl.UnsafeEnabled {
mi := &file_pairing_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *PairDeviceData) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PairDeviceData) ProtoMessage() {}
func (x *PairDeviceData) ProtoReflect() protoreflect.Message {
mi := &file_pairing_proto_msgTypes[3]
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 PairDeviceData.ProtoReflect.Descriptor instead.
func (*PairDeviceData) Descriptor() ([]byte, []int) {
return file_pairing_proto_rawDescGZIP(), []int{3}
}
func (x *PairDeviceData) GetMobile() *Device {
if x != nil {
return x.Mobile
}
return nil
}
func (x *PairDeviceData) GetEcdsaKeys() *ECDSAKeys {
if x != nil {
return x.EcdsaKeys
}
return nil
}
func (x *PairDeviceData) GetWebAuthKeyData() *WebAuthKey {
if x != nil {
return x.WebAuthKeyData
}
return nil
}
func (x *PairDeviceData) GetBrowser() *Device {
if x != nil {
return x.Browser
}
return nil
}
type WebAuthKey struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
WebAuthKey []byte `protobuf:"bytes,1,opt,name=webAuthKey,proto3" json:"webAuthKey,omitempty"`
ValidFor int64 `protobuf:"varint,2,opt,name=validFor,proto3" json:"validFor,omitempty"`
}
func (x *WebAuthKey) Reset() {
*x = WebAuthKey{}
if protoimpl.UnsafeEnabled {
mi := &file_pairing_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *WebAuthKey) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*WebAuthKey) ProtoMessage() {}
func (x *WebAuthKey) ProtoReflect() protoreflect.Message {
mi := &file_pairing_proto_msgTypes[4]
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 WebAuthKey.ProtoReflect.Descriptor instead.
func (*WebAuthKey) Descriptor() ([]byte, []int) {
return file_pairing_proto_rawDescGZIP(), []int{4}
}
func (x *WebAuthKey) GetWebAuthKey() []byte {
if x != nil {
return x.WebAuthKey
}
return nil
}
func (x *WebAuthKey) GetValidFor() int64 {
if x != nil {
return x.ValidFor
}
return 0
}
type Container struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
PhoneRelay *PhoneRelayBody `protobuf:"bytes,1,opt,name=PhoneRelay,proto3" json:"PhoneRelay,omitempty"`
BrowserDetails *BrowserDetails `protobuf:"bytes,3,opt,name=browserDetails,proto3" json:"browserDetails,omitempty"`
PairDeviceData *PairDeviceData `protobuf:"bytes,4,opt,name=pairDeviceData,proto3" json:"pairDeviceData,omitempty"`
}
func (x *Container) Reset() {
*x = Container{}
if protoimpl.UnsafeEnabled {
mi := &file_pairing_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Container) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Container) ProtoMessage() {}
func (x *Container) ProtoReflect() protoreflect.Message {
mi := &file_pairing_proto_msgTypes[5]
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 Container.ProtoReflect.Descriptor instead.
func (*Container) Descriptor() ([]byte, []int) {
return file_pairing_proto_rawDescGZIP(), []int{5}
}
func (x *Container) GetPhoneRelay() *PhoneRelayBody {
if x != nil {
return x.PhoneRelay
}
return nil
}
func (x *Container) GetBrowserDetails() *BrowserDetails {
if x != nil {
return x.BrowserDetails
}
return nil
}
func (x *Container) GetPairDeviceData() *PairDeviceData {
if x != nil {
return x.PairDeviceData
}
return nil
}
type UrlData struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
PairingKey []byte `protobuf:"bytes,1,opt,name=pairingKey,proto3" json:"pairingKey,omitempty"`
AES_CTR_KEY_256 []byte `protobuf:"bytes,2,opt,name=AES_CTR_KEY_256,json=AESCTRKEY256,proto3" json:"AES_CTR_KEY_256,omitempty"`
SHA_256_KEY []byte `protobuf:"bytes,3,opt,name=SHA_256_KEY,json=SHA256KEY,proto3" json:"SHA_256_KEY,omitempty"`
}
func (x *UrlData) Reset() {
*x = UrlData{}
if protoimpl.UnsafeEnabled {
mi := &file_pairing_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *UrlData) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*UrlData) ProtoMessage() {}
func (x *UrlData) ProtoReflect() protoreflect.Message {
mi := &file_pairing_proto_msgTypes[6]
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 UrlData.ProtoReflect.Descriptor instead.
func (*UrlData) Descriptor() ([]byte, []int) {
return file_pairing_proto_rawDescGZIP(), []int{6}
}
func (x *UrlData) GetPairingKey() []byte {
if x != nil {
return x.PairingKey
}
return nil
}
func (x *UrlData) GetAES_CTR_KEY_256() []byte {
if x != nil {
return x.AES_CTR_KEY_256
}
return nil
}
func (x *UrlData) GetSHA_256_KEY() []byte {
if x != nil {
return x.SHA_256_KEY
}
return nil
}
var File_pairing_proto protoreflect.FileDescriptor
var file_pairing_proto_rawDesc = []byte{
0x0a, 0x0d, 0x70, 0x61, 0x69, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
0x07, 0x70, 0x61, 0x69, 0x72, 0x69, 0x6e, 0x67, 0x1a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x75, 0x0a, 0x0e, 0x42, 0x72, 0x6f, 0x77,
0x73, 0x65, 0x72, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73,
0x65, 0x72, 0x5f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x6f, 0x6d,
0x65, 0x49, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x73, 0x6f, 0x6d, 0x65,
0x49, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x02, 0x6f, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x6f, 0x6d, 0x65, 0x42, 0x6f, 0x6f, 0x6c, 0x18,
0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x73, 0x6f, 0x6d, 0x65, 0x42, 0x6f, 0x6f, 0x6c, 0x22,
0x72, 0x0a, 0x0e, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x6f, 0x64,
0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69,
0x64, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x75, 0x67, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
0x52, 0x05, 0x62, 0x75, 0x67, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x70, 0x63, 0x4b, 0x65,
0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x70, 0x63, 0x4b, 0x65, 0x79, 0x12,
0x22, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e,
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x44, 0x61, 0x74, 0x65, 0x52, 0x04, 0x64,
0x61, 0x74, 0x65, 0x22, 0x55, 0x0a, 0x09, 0x45, 0x43, 0x44, 0x53, 0x41, 0x4b, 0x65, 0x79, 0x73,
0x12, 0x22, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x56, 0x65, 0x72,
0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65,
0x64, 0x4b, 0x65, 0x79, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x65, 0x6e, 0x63,
0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x22, 0xd5, 0x01, 0x0a, 0x0e, 0x50,
0x61, 0x69, 0x72, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x28, 0x0a,
0x06, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e,
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52,
0x06, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x12, 0x30, 0x0a, 0x09, 0x65, 0x63, 0x64, 0x73, 0x61,
0x4b, 0x65, 0x79, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x61, 0x69,
0x72, 0x69, 0x6e, 0x67, 0x2e, 0x45, 0x43, 0x44, 0x53, 0x41, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x09,
0x65, 0x63, 0x64, 0x73, 0x61, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x3b, 0x0a, 0x0e, 0x77, 0x65, 0x62,
0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x44, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x13, 0x2e, 0x70, 0x61, 0x69, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x57, 0x65, 0x62, 0x41,
0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x52, 0x0e, 0x77, 0x65, 0x62, 0x41, 0x75, 0x74, 0x68, 0x4b,
0x65, 0x79, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2a, 0x0a, 0x07, 0x62, 0x72, 0x6f, 0x77, 0x73, 0x65,
0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x73, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x07, 0x62, 0x72, 0x6f, 0x77, 0x73,
0x65, 0x72, 0x22, 0x48, 0x0a, 0x0a, 0x57, 0x65, 0x62, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79,
0x12, 0x1e, 0x0a, 0x0a, 0x77, 0x65, 0x62, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x77, 0x65, 0x62, 0x41, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79,
0x12, 0x1a, 0x0a, 0x08, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x46, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01,
0x28, 0x03, 0x52, 0x08, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x46, 0x6f, 0x72, 0x22, 0xc6, 0x01, 0x0a,
0x09, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x37, 0x0a, 0x0a, 0x50, 0x68,
0x6f, 0x6e, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17,
0x2e, 0x70, 0x61, 0x69, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x52, 0x65,
0x6c, 0x61, 0x79, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x0a, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x52, 0x65,
0x6c, 0x61, 0x79, 0x12, 0x3f, 0x0a, 0x0e, 0x62, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x44, 0x65,
0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x61,
0x69, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x42, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x44, 0x65, 0x74,
0x61, 0x69, 0x6c, 0x73, 0x52, 0x0e, 0x62, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x44, 0x65, 0x74,
0x61, 0x69, 0x6c, 0x73, 0x12, 0x3f, 0x0a, 0x0e, 0x70, 0x61, 0x69, 0x72, 0x44, 0x65, 0x76, 0x69,
0x63, 0x65, 0x44, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70,
0x61, 0x69, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x61, 0x69, 0x72, 0x44, 0x65, 0x76, 0x69, 0x63,
0x65, 0x44, 0x61, 0x74, 0x61, 0x52, 0x0e, 0x70, 0x61, 0x69, 0x72, 0x44, 0x65, 0x76, 0x69, 0x63,
0x65, 0x44, 0x61, 0x74, 0x61, 0x22, 0x70, 0x0a, 0x07, 0x55, 0x72, 0x6c, 0x44, 0x61, 0x74, 0x61,
0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x61, 0x69, 0x72, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x61, 0x69, 0x72, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79,
0x12, 0x25, 0x0a, 0x0f, 0x41, 0x45, 0x53, 0x5f, 0x43, 0x54, 0x52, 0x5f, 0x4b, 0x45, 0x59, 0x5f,
0x32, 0x35, 0x36, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x41, 0x45, 0x53, 0x43, 0x54,
0x52, 0x4b, 0x45, 0x59, 0x32, 0x35, 0x36, 0x12, 0x1e, 0x0a, 0x0b, 0x53, 0x48, 0x41, 0x5f, 0x32,
0x35, 0x36, 0x5f, 0x4b, 0x45, 0x59, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x53, 0x48,
0x41, 0x32, 0x35, 0x36, 0x4b, 0x45, 0x59, 0x42, 0x0e, 0x5a, 0x0c, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e,
0x2f, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_pairing_proto_rawDescOnce sync.Once
file_pairing_proto_rawDescData = file_pairing_proto_rawDesc
)
func file_pairing_proto_rawDescGZIP() []byte {
file_pairing_proto_rawDescOnce.Do(func() {
file_pairing_proto_rawDescData = protoimpl.X.CompressGZIP(file_pairing_proto_rawDescData)
})
return file_pairing_proto_rawDescData
}
var file_pairing_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_pairing_proto_goTypes = []interface{}{
(*BrowserDetails)(nil), // 0: pairing.BrowserDetails
(*PhoneRelayBody)(nil), // 1: pairing.PhoneRelayBody
(*ECDSAKeys)(nil), // 2: pairing.ECDSAKeys
(*PairDeviceData)(nil), // 3: pairing.PairDeviceData
(*WebAuthKey)(nil), // 4: pairing.WebAuthKey
(*Container)(nil), // 5: pairing.Container
(*UrlData)(nil), // 6: pairing.UrlData
(*Date)(nil), // 7: messages.Date
(*Device)(nil), // 8: messages.Device
}
var file_pairing_proto_depIdxs = []int32{
7, // 0: pairing.PhoneRelayBody.date:type_name -> messages.Date
8, // 1: pairing.PairDeviceData.mobile:type_name -> messages.Device
2, // 2: pairing.PairDeviceData.ecdsaKeys:type_name -> pairing.ECDSAKeys
4, // 3: pairing.PairDeviceData.webAuthKeyData:type_name -> pairing.WebAuthKey
8, // 4: pairing.PairDeviceData.browser:type_name -> messages.Device
1, // 5: pairing.Container.PhoneRelay:type_name -> pairing.PhoneRelayBody
0, // 6: pairing.Container.browserDetails:type_name -> pairing.BrowserDetails
3, // 7: pairing.Container.pairDeviceData:type_name -> pairing.PairDeviceData
8, // [8:8] is the sub-list for method output_type
8, // [8:8] is the sub-list for method input_type
8, // [8:8] is the sub-list for extension type_name
8, // [8:8] is the sub-list for extension extendee
0, // [0:8] is the sub-list for field type_name
}
func init() { file_pairing_proto_init() }
func file_pairing_proto_init() {
if File_pairing_proto != nil {
return
}
file_messages_proto_init()
if !protoimpl.UnsafeEnabled {
file_pairing_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*BrowserDetails); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_pairing_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*PhoneRelayBody); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_pairing_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ECDSAKeys); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_pairing_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*PairDeviceData); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_pairing_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*WebAuthKey); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_pairing_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Container); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_pairing_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*UrlData); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_pairing_proto_rawDesc,
NumEnums: 0,
NumMessages: 7,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_pairing_proto_goTypes,
DependencyIndexes: file_pairing_proto_depIdxs,
MessageInfos: file_pairing_proto_msgTypes,
}.Build()
File_pairing_proto = out.File
file_pairing_proto_rawDesc = nil
file_pairing_proto_goTypes = nil
file_pairing_proto_depIdxs = nil
}

22
libgm/binary/protoUtil.go Normal file
View file

@ -0,0 +1,22 @@
package binary
import (
"fmt"
"google.golang.org/protobuf/proto"
)
func EncodeProtoMessage(message proto.Message) ([]byte, error) {
data, err := proto.Marshal(message)
if err != nil {
return nil, fmt.Errorf("failed to encode proto message: %v", err)
}
return data, nil
}
func DecodeProtoMessage(data []byte, message proto.Message) error {
err := proto.Unmarshal(data, message)
if err != nil {
return fmt.Errorf("failed to decode proto message: %v", err)
}
return nil
}

View file

@ -0,0 +1,43 @@
syntax = "proto3";
package client;
option go_package = "../../binary";
import "messages.proto";
message SendMessage {
messages.Device pairedDevice = 1;
messages.MessageData messageData = 2;
messages.AuthMessage authData = 3;
int64 ttl = 5;
messages.EmptyArr emptyArr = 9;
}
message AckMessagePayload {
messages.AuthMessage authData = 1;
messages.EmptyArr emptyArr = 2;
bytes noClue = 3;
}
message AckMessageData {
string request_id = 1;
messages.Device device = 2;
}
message ImageMetaData {
string imageId = 1;
bool encrypted = 2;
}
message UploadImagePayload {
ImageMetaData metaData = 1;
messages.AuthMessageBytes authData = 2;
}
message BugleBackendService {
BugleCode data = 6;
}
message BugleCode {
int64 type = 2;
}

View file

@ -0,0 +1,194 @@
syntax = "proto3";
package conversations;
option go_package = "../../binary";
message SendMessagePayload {
string conversationId = 2;
MessagePayload messagePayload = 3;
string tmpId = 5;
}
message MessagePayload {
string tmpId = 1;
MessagePayloadContent messagePayloadContent = 6;
string conversationId = 7;
string selfParticipantId = 9; // might be participantId
repeated MessageInfo messageInfo = 10;
string tmpId2 = 12;
}
message MessagePayloadContent {
MessageContent messageContent = 1;
}
message OpenConversationPayload {
string conversationId = 2;
}
message PrepareOpenConversationPayload {
int64 field2 = 2; // only seen value 1
}
message FetchConversationMessagesPayload {
string conversationId = 2;
int64 count = 3;
Cursor cursor = 5;
}
message ListCoversationsPayload {
int64 count = 2; // no idea if this is actually amount to list
int64 field4 = 4; // no idea what this is , but only value ive seen is 1
}
message FetchMessagesResponse {
repeated Message messages = 2;
bytes someBytes = 3;
int64 totalMessages = 4;
Cursor cursor = 5;
}
message Cursor {
string someStr = 1;
int64 nextCursor = 2;
}
enum MessageType {
UNKNOWN = 0;
TEXT = 1;
IMAGE = 2;
VIDEO = 3;
AUDIO = 4;
ATTACHMENT = 5;
LOCATION = 6;
RICH_CARD = 7;
VCARD = 8;
MMS_NEEDS_DOWNLOAD = 9;
REPLY = 10;
}
message Message {
string messageId = 1;
IsFromMe from = 3;
MessageStatus messageStatus = 4;
int64 timestamp = 5;
string conversationId = 7;
string participantId = 9;
repeated MessageInfo messageInfo = 10;
MessageType type = 11;
string tmpId = 12;
}
message MessageInfo {
string orderInternal = 1;
oneof data {
MessageContent messageContent = 2;
ImageContent imageContent = 3;
}
}
message ImageContent {
int64 someNumber = 1;
string imageId = 2;
string imageName = 4;
int64 size = 5;
ImagePixels pixels = 6;
bytes imageData = 7;
string imageId2 = 9;
bytes decryptionKey = 11;
bytes decryptionKey2 = 12; // same value as decryptionkey?
}
message ImagePixels {
int64 width = 1;
int64 height = 2;
}
message MessageContent {
string content = 1;
}
message IsFromMe {
bool fromMe = 1;
}
enum MsgStatusCode {
UNKNOWN_STATUS = 0;
SENDING = 5;
SENT = 1;
}
message MessageStatus {
/*
// MMS / SMS
UNKNOWN_STATUS = 0;
SENDING = 5;
SENT = 1;
// RCS
READ|SEEN = 11;
*/
int64 code = 2;
string errMsg = 4;
string msgStatus = 5;
}
message Conversations {
repeated Conversation conversations = 2;
}
message Conversation {
string conversationId = 1;
string name = 2;
LatestMessage latestMessage = 4;
int64 timestampMs = 5;
bool isGroupChat = 10; // not certain
string selfParticipantId = 11;
/*
1 = unarchived
2 = archived
3 = deleted
*/
//bool bool1 = 13;
int64 status = 12;
string hashHex = 15;
string messageId = 17;
repeated Participant participants = 20;
repeated string otherParticipants = 21; // participant ids excluding me
int64 type = 22;
}
message Participant {
SmallInfo smallInfo = 1;
string hashHex = 5;
bool isMe = 6;
Muted muted = 7;
//bool bool2 = 8;
int64 bs = 14;
string displayName = 15;
}
message SmallInfo {
int64 type = 1;
string number = 2;
string participantId = 3;
}
message LatestMessage {
string content = 1;
bool fromMe = 2; // isMe?
string displayName = 4;
//Unknown unknown = 5;
}
message Unknown {
int64 field1 = 1;
int64 field2 = 2;
}
message Muted {
bool isMuted = 1;
}

View file

@ -0,0 +1,58 @@
syntax = "proto3";
package events;
option go_package = "../../binary";
import "settings.proto";
import "messages.proto";
import "conversations.proto";
/*
Cases
2 = CONVERSATION
3 = MESSAGE
5 = PHONE SETTINGS
6 = Cases
2 = updated session
8 = INACTIVE_LACK_OF_ACTIVITY
7 = BROWSER_INACTIVE_FROM_TIMEOUT
6|5 = user_alert:battery
3|4 = user_alert:data_connection
10 = OBSERVER_REGISTERED
*/
message Event {
oneof event {
ConversationEvent conversationEvent = 2;
MessageEvent messageEvent = 3;
UserAlertEvent userAlertEvent = 6;
}
}
message ConversationEvent {
conversations.Conversation data = 2;
}
message MessageEvent {
conversations.Message data = 2;
}
message UserAlertEvent {
/*
2 = BROWSER_ACTIVE (new session created in other browser)
1 = ?
8 = INACTIVE_LACK_OF_ACTIVITY
7 = INACTIVE_TIMEOUT
5|6 = BATTERY (tf?)
3|4 = DATA_CONNECTION (tf?)
10 = OBSERVER_REGISTERED (tf?)
*/
int64 alert_type = 2;
}

View file

@ -0,0 +1,22 @@
syntax = "proto3";
package media;
option go_package = "../../binary";
import "messages.proto";
message StartMediaUploadPayload {
int64 imageType = 1;
messages.AuthMessageBytes authData = 2;
messages.Device mobile = 3;
}
message UploadMediaResponse {
Media media = 1;
string message = 2;
}
message Media {
string mediaId = 1;
int64 mediaNumber = 2;
}

View file

@ -0,0 +1,82 @@
syntax = "proto3";
package messages;
option go_package = "../../binary";
message EncodedPayload {
string request_id = 1;
int64 opcode = 2;
bytes encryptedData = 5;
string session_id = 6;
}
message EncodedResponse {
string request_id = 1;
//int64 msg = 2;
int64 unixNano = 3;
int64 opcode = 4;
//bytes keyData = 5;
bool sub = 6;
int64 third = 7;
bytes encryptedData = 8;
bool field9 = 9;
}
message MessageData {
string request_id = 1;
int64 routing_op_code = 2;
string ts1 = 3;
int64 field5 = 5;
string ts2 = 6;
string someString = 7;
Device mobile = 8;
Device browser = 9;
string encodedData = 12;
string encoded_request_id = 17;
MsgTypeArr msgTypeArr = 23;
}
message MsgTypeArr {
EmptyArr emptyArr = 1;
int64 msgType = 2;
}
message EmptyArr {
}
message AuthMessage {
string request_id = 1;
string rpcKey = 6;
Date date = 7;
}
message AuthMessageBytes {
string request_id = 1;
bytes rpcKey = 6;
Date date = 7;
}
message BaseData {
int64 Ttl = 2;
EmptyArr emptyArr = 6;
}
message RPCResponse {
bytes unknown = 1;
MessageData data = 2;
}
message Device {
int64 userId = 1;
string registrationId = 2;
string network = 3;
}
message Date {
int64 year = 3;
int64 seq1 = 4;
int64 seq2 = 5;
int64 seq3 = 7;
int64 seq4 = 9;
}

View file

@ -0,0 +1,49 @@
syntax = "proto3";
package pairing;
option go_package = "../../binary";
import "messages.proto";
message BrowserDetails {
string user_agent = 1;
int32 someInt = 2;
string os = 3;
bool someBool = 6;
}
message PhoneRelayBody {
string id = 1;
string bugle = 3;
bytes rpcKey = 6;
messages.Date date = 7;
}
message ECDSAKeys {
int64 protoVersion = 1; // idk?
bytes encryptedKeys = 2;
}
message PairDeviceData {
messages.Device mobile = 1;
ECDSAKeys ecdsaKeys = 6;
WebAuthKey webAuthKeyData = 2;
messages.Device browser = 3;
}
message WebAuthKey {
bytes webAuthKey = 1;
int64 validFor = 2;
}
message Container {
PhoneRelayBody PhoneRelay = 1;
BrowserDetails browserDetails = 3;
PairDeviceData pairDeviceData = 4;
}
message UrlData {
bytes pairingKey = 1;
bytes AES_CTR_KEY_256 = 2;
bytes SHA_256_KEY = 3;
}

View file

@ -0,0 +1,39 @@
syntax = "proto3";
package registerPhoneRelay;
option go_package = "../../binary";
message RegisterPhoneRelayResponse {
Message1 field1 = 1;
Message2 field2 = 2;
bytes PairingKey = 3;
int64 field4 = 4;
Message3 field5 = 5;
bytes field6 = 6;
}
message Message1 {
int64 pubKey = 2;
}
message Message2 {
int64 field1 = 1;
bytes field2 = 2;
string field3 = 3;
}
message Message3 {
bytes rpcKey = 1;
int64 field2 = 2;
}
message RefreshPhoneRelayResponse {
Message1 field1 = 1;
bytes pairKey = 2;
int64 validFor = 3;
}
message WebEncryptionKeyResponse {
Message1 curve = 1;
bytes key = 2;
}

View file

@ -0,0 +1,19 @@
syntax = "proto3";
package responses;
option go_package = "../../binary";
import "settings.proto";
import "conversations.proto";
message PrepareNewSession {
bool success = 1;
}
message NewSession {
settings.Settings settings = 5;
}
message SendMessageResponse {
conversations.MessageType type = 3;
}

View file

@ -0,0 +1,75 @@
syntax = "proto3";
package settings;
option go_package = "../../binary";
message Settings {
Data data = 2;
OpCodeData opCodeData = 3;
BooleanFields boolFields = 4;
string version = 5;
bool bool1 = 7;
BooleanFields2 boolFields2 = 8;
string emptyString = 9;
BooleanFields3 boolFields3 = 10;
}
message Data { // i think its simdata? no clue
BoolMsg boolMsg = 3;
SimData simData = 5;
bool bool1 = 6;
NoClue noClue = 7;
}
message BoolMsg {
bool bool1 = 1;
}
message SimData {
UnknownMessage unknownMessage = 1;
bool bool1 = 2;
string carrierName = 3;
string hexHash = 4;
int64 int1 = 5;
}
message UnknownMessage {
int64 int1 = 1;
int64 int2 = 2;
}
message NoClue { // just a guess lol
string count = 1;
}
message OpCodeData {
bool field7 = 7;
string jsonData = 16;
}
message BooleanFields {
bool bool1 = 1;
bool bool2 = 2;
bool bool3 = 3;
bool bool4 = 4;
}
message BooleanFields2 {
bool bool1 = 1;
bool bool2 = 2;
BoolMsg boolMsg1 = 3;
BoolMsg boolMsg2 = 5;
bool bool3 = 6;
}
message BooleanFields3 {
bool bool1 = 1;
bool bool3 = 3;
bool bool4 = 4;
bool bool5 = 5;
bool bool6 = 6;
bool bool7 = 7;
bool bool8 = 8;
bool bool9 = 9;
}

576
libgm/binary/relay.pb.go Normal file
View file

@ -0,0 +1,576 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.30.0
// protoc v3.21.12
// source: relay.proto
package binary
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type RegisterPhoneRelayResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Field1 *Message1 `protobuf:"bytes,1,opt,name=field1,proto3" json:"field1,omitempty"`
Field2 *Message2 `protobuf:"bytes,2,opt,name=field2,proto3" json:"field2,omitempty"`
PairingKey []byte `protobuf:"bytes,3,opt,name=PairingKey,proto3" json:"PairingKey,omitempty"`
Field4 int64 `protobuf:"varint,4,opt,name=field4,proto3" json:"field4,omitempty"`
Field5 *Message3 `protobuf:"bytes,5,opt,name=field5,proto3" json:"field5,omitempty"`
Field6 []byte `protobuf:"bytes,6,opt,name=field6,proto3" json:"field6,omitempty"`
}
func (x *RegisterPhoneRelayResponse) Reset() {
*x = RegisterPhoneRelayResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_relay_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RegisterPhoneRelayResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RegisterPhoneRelayResponse) ProtoMessage() {}
func (x *RegisterPhoneRelayResponse) ProtoReflect() protoreflect.Message {
mi := &file_relay_proto_msgTypes[0]
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 RegisterPhoneRelayResponse.ProtoReflect.Descriptor instead.
func (*RegisterPhoneRelayResponse) Descriptor() ([]byte, []int) {
return file_relay_proto_rawDescGZIP(), []int{0}
}
func (x *RegisterPhoneRelayResponse) GetField1() *Message1 {
if x != nil {
return x.Field1
}
return nil
}
func (x *RegisterPhoneRelayResponse) GetField2() *Message2 {
if x != nil {
return x.Field2
}
return nil
}
func (x *RegisterPhoneRelayResponse) GetPairingKey() []byte {
if x != nil {
return x.PairingKey
}
return nil
}
func (x *RegisterPhoneRelayResponse) GetField4() int64 {
if x != nil {
return x.Field4
}
return 0
}
func (x *RegisterPhoneRelayResponse) GetField5() *Message3 {
if x != nil {
return x.Field5
}
return nil
}
func (x *RegisterPhoneRelayResponse) GetField6() []byte {
if x != nil {
return x.Field6
}
return nil
}
type Message1 struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
PubKey int64 `protobuf:"varint,2,opt,name=pubKey,proto3" json:"pubKey,omitempty"`
}
func (x *Message1) Reset() {
*x = Message1{}
if protoimpl.UnsafeEnabled {
mi := &file_relay_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Message1) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Message1) ProtoMessage() {}
func (x *Message1) ProtoReflect() protoreflect.Message {
mi := &file_relay_proto_msgTypes[1]
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 Message1.ProtoReflect.Descriptor instead.
func (*Message1) Descriptor() ([]byte, []int) {
return file_relay_proto_rawDescGZIP(), []int{1}
}
func (x *Message1) GetPubKey() int64 {
if x != nil {
return x.PubKey
}
return 0
}
type Message2 struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Field1 int64 `protobuf:"varint,1,opt,name=field1,proto3" json:"field1,omitempty"`
Field2 []byte `protobuf:"bytes,2,opt,name=field2,proto3" json:"field2,omitempty"`
Field3 string `protobuf:"bytes,3,opt,name=field3,proto3" json:"field3,omitempty"`
}
func (x *Message2) Reset() {
*x = Message2{}
if protoimpl.UnsafeEnabled {
mi := &file_relay_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Message2) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Message2) ProtoMessage() {}
func (x *Message2) ProtoReflect() protoreflect.Message {
mi := &file_relay_proto_msgTypes[2]
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 Message2.ProtoReflect.Descriptor instead.
func (*Message2) Descriptor() ([]byte, []int) {
return file_relay_proto_rawDescGZIP(), []int{2}
}
func (x *Message2) GetField1() int64 {
if x != nil {
return x.Field1
}
return 0
}
func (x *Message2) GetField2() []byte {
if x != nil {
return x.Field2
}
return nil
}
func (x *Message2) GetField3() string {
if x != nil {
return x.Field3
}
return ""
}
type Message3 struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
RpcKey []byte `protobuf:"bytes,1,opt,name=rpcKey,proto3" json:"rpcKey,omitempty"`
Field2 int64 `protobuf:"varint,2,opt,name=field2,proto3" json:"field2,omitempty"`
}
func (x *Message3) Reset() {
*x = Message3{}
if protoimpl.UnsafeEnabled {
mi := &file_relay_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Message3) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Message3) ProtoMessage() {}
func (x *Message3) ProtoReflect() protoreflect.Message {
mi := &file_relay_proto_msgTypes[3]
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 Message3.ProtoReflect.Descriptor instead.
func (*Message3) Descriptor() ([]byte, []int) {
return file_relay_proto_rawDescGZIP(), []int{3}
}
func (x *Message3) GetRpcKey() []byte {
if x != nil {
return x.RpcKey
}
return nil
}
func (x *Message3) GetField2() int64 {
if x != nil {
return x.Field2
}
return 0
}
type RefreshPhoneRelayResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Field1 *Message1 `protobuf:"bytes,1,opt,name=field1,proto3" json:"field1,omitempty"`
PairKey []byte `protobuf:"bytes,2,opt,name=pairKey,proto3" json:"pairKey,omitempty"`
ValidFor int64 `protobuf:"varint,3,opt,name=validFor,proto3" json:"validFor,omitempty"`
}
func (x *RefreshPhoneRelayResponse) Reset() {
*x = RefreshPhoneRelayResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_relay_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RefreshPhoneRelayResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RefreshPhoneRelayResponse) ProtoMessage() {}
func (x *RefreshPhoneRelayResponse) ProtoReflect() protoreflect.Message {
mi := &file_relay_proto_msgTypes[4]
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 RefreshPhoneRelayResponse.ProtoReflect.Descriptor instead.
func (*RefreshPhoneRelayResponse) Descriptor() ([]byte, []int) {
return file_relay_proto_rawDescGZIP(), []int{4}
}
func (x *RefreshPhoneRelayResponse) GetField1() *Message1 {
if x != nil {
return x.Field1
}
return nil
}
func (x *RefreshPhoneRelayResponse) GetPairKey() []byte {
if x != nil {
return x.PairKey
}
return nil
}
func (x *RefreshPhoneRelayResponse) GetValidFor() int64 {
if x != nil {
return x.ValidFor
}
return 0
}
type WebEncryptionKeyResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Curve *Message1 `protobuf:"bytes,1,opt,name=curve,proto3" json:"curve,omitempty"`
Key []byte `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
}
func (x *WebEncryptionKeyResponse) Reset() {
*x = WebEncryptionKeyResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_relay_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *WebEncryptionKeyResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*WebEncryptionKeyResponse) ProtoMessage() {}
func (x *WebEncryptionKeyResponse) ProtoReflect() protoreflect.Message {
mi := &file_relay_proto_msgTypes[5]
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 WebEncryptionKeyResponse.ProtoReflect.Descriptor instead.
func (*WebEncryptionKeyResponse) Descriptor() ([]byte, []int) {
return file_relay_proto_rawDescGZIP(), []int{5}
}
func (x *WebEncryptionKeyResponse) GetCurve() *Message1 {
if x != nil {
return x.Curve
}
return nil
}
func (x *WebEncryptionKeyResponse) GetKey() []byte {
if x != nil {
return x.Key
}
return nil
}
var File_relay_proto protoreflect.FileDescriptor
var file_relay_proto_rawDesc = []byte{
0x0a, 0x0b, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x72,
0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x6c, 0x61,
0x79, 0x22, 0x8e, 0x02, 0x0a, 0x1a, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x68,
0x6f, 0x6e, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x34, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x1c, 0x2e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x68, 0x6f, 0x6e, 0x65,
0x52, 0x65, 0x6c, 0x61, 0x79, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x31, 0x52, 0x06,
0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x12, 0x34, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65,
0x72, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x2e, 0x4d, 0x65, 0x73, 0x73,
0x61, 0x67, 0x65, 0x32, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x12, 0x1e, 0x0a, 0x0a,
0x50, 0x61, 0x69, 0x72, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c,
0x52, 0x0a, 0x50, 0x61, 0x69, 0x72, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06,
0x66, 0x69, 0x65, 0x6c, 0x64, 0x34, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x66, 0x69,
0x65, 0x6c, 0x64, 0x34, 0x12, 0x34, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x35, 0x18, 0x05,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50,
0x68, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x33, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x35, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69,
0x65, 0x6c, 0x64, 0x36, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c,
0x64, 0x36, 0x22, 0x22, 0x0a, 0x08, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x31, 0x12, 0x16,
0x0a, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06,
0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x52, 0x0a, 0x08, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x32, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x18, 0x01, 0x20, 0x01,
0x28, 0x03, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69,
0x65, 0x6c, 0x64, 0x32, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c,
0x64, 0x32, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x18, 0x03, 0x20, 0x01,
0x28, 0x09, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x33, 0x22, 0x3a, 0x0a, 0x08, 0x4d, 0x65,
0x73, 0x73, 0x61, 0x67, 0x65, 0x33, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x70, 0x63, 0x4b, 0x65, 0x79,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x70, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x16,
0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06,
0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x22, 0x87, 0x01, 0x0a, 0x19, 0x52, 0x65, 0x66, 0x72, 0x65,
0x73, 0x68, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50,
0x68, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x31, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61,
0x69, 0x72, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x69,
0x72, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x46, 0x6f, 0x72,
0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x46, 0x6f, 0x72,
0x22, 0x60, 0x0a, 0x18, 0x57, 0x65, 0x62, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f,
0x6e, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x05,
0x63, 0x75, 0x72, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x72, 0x65,
0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79,
0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x31, 0x52, 0x05, 0x63, 0x75, 0x72, 0x76, 0x65,
0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b,
0x65, 0x79, 0x42, 0x0e, 0x5a, 0x0c, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x62, 0x69, 0x6e, 0x61,
0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_relay_proto_rawDescOnce sync.Once
file_relay_proto_rawDescData = file_relay_proto_rawDesc
)
func file_relay_proto_rawDescGZIP() []byte {
file_relay_proto_rawDescOnce.Do(func() {
file_relay_proto_rawDescData = protoimpl.X.CompressGZIP(file_relay_proto_rawDescData)
})
return file_relay_proto_rawDescData
}
var file_relay_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_relay_proto_goTypes = []interface{}{
(*RegisterPhoneRelayResponse)(nil), // 0: registerPhoneRelay.RegisterPhoneRelayResponse
(*Message1)(nil), // 1: registerPhoneRelay.Message1
(*Message2)(nil), // 2: registerPhoneRelay.Message2
(*Message3)(nil), // 3: registerPhoneRelay.Message3
(*RefreshPhoneRelayResponse)(nil), // 4: registerPhoneRelay.RefreshPhoneRelayResponse
(*WebEncryptionKeyResponse)(nil), // 5: registerPhoneRelay.WebEncryptionKeyResponse
}
var file_relay_proto_depIdxs = []int32{
1, // 0: registerPhoneRelay.RegisterPhoneRelayResponse.field1:type_name -> registerPhoneRelay.Message1
2, // 1: registerPhoneRelay.RegisterPhoneRelayResponse.field2:type_name -> registerPhoneRelay.Message2
3, // 2: registerPhoneRelay.RegisterPhoneRelayResponse.field5:type_name -> registerPhoneRelay.Message3
1, // 3: registerPhoneRelay.RefreshPhoneRelayResponse.field1:type_name -> registerPhoneRelay.Message1
1, // 4: registerPhoneRelay.WebEncryptionKeyResponse.curve:type_name -> registerPhoneRelay.Message1
5, // [5:5] is the sub-list for method output_type
5, // [5:5] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
}
func init() { file_relay_proto_init() }
func file_relay_proto_init() {
if File_relay_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_relay_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RegisterPhoneRelayResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_relay_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Message1); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_relay_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Message2); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_relay_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Message3); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_relay_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RefreshPhoneRelayResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_relay_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*WebEncryptionKeyResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_relay_proto_rawDesc,
NumEnums: 0,
NumMessages: 6,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_relay_proto_goTypes,
DependencyIndexes: file_relay_proto_depIdxs,
MessageInfos: file_relay_proto_msgTypes,
}.Build()
File_relay_proto = out.File
file_relay_proto_rawDesc = nil
file_relay_proto_goTypes = nil
file_relay_proto_depIdxs = nil
}

View file

@ -0,0 +1,279 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.30.0
// protoc v3.21.12
// source: responses.proto
package binary
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type PrepareNewSession struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
}
func (x *PrepareNewSession) Reset() {
*x = PrepareNewSession{}
if protoimpl.UnsafeEnabled {
mi := &file_responses_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *PrepareNewSession) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PrepareNewSession) ProtoMessage() {}
func (x *PrepareNewSession) ProtoReflect() protoreflect.Message {
mi := &file_responses_proto_msgTypes[0]
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 PrepareNewSession.ProtoReflect.Descriptor instead.
func (*PrepareNewSession) Descriptor() ([]byte, []int) {
return file_responses_proto_rawDescGZIP(), []int{0}
}
func (x *PrepareNewSession) GetSuccess() bool {
if x != nil {
return x.Success
}
return false
}
type NewSession struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Settings *Settings `protobuf:"bytes,5,opt,name=settings,proto3" json:"settings,omitempty"`
}
func (x *NewSession) Reset() {
*x = NewSession{}
if protoimpl.UnsafeEnabled {
mi := &file_responses_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *NewSession) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NewSession) ProtoMessage() {}
func (x *NewSession) ProtoReflect() protoreflect.Message {
mi := &file_responses_proto_msgTypes[1]
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 NewSession.ProtoReflect.Descriptor instead.
func (*NewSession) Descriptor() ([]byte, []int) {
return file_responses_proto_rawDescGZIP(), []int{1}
}
func (x *NewSession) GetSettings() *Settings {
if x != nil {
return x.Settings
}
return nil
}
type SendMessageResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Type MessageType `protobuf:"varint,3,opt,name=type,proto3,enum=conversations.MessageType" json:"type,omitempty"`
}
func (x *SendMessageResponse) Reset() {
*x = SendMessageResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_responses_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SendMessageResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SendMessageResponse) ProtoMessage() {}
func (x *SendMessageResponse) ProtoReflect() protoreflect.Message {
mi := &file_responses_proto_msgTypes[2]
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 SendMessageResponse.ProtoReflect.Descriptor instead.
func (*SendMessageResponse) Descriptor() ([]byte, []int) {
return file_responses_proto_rawDescGZIP(), []int{2}
}
func (x *SendMessageResponse) GetType() MessageType {
if x != nil {
return x.Type
}
return MessageType_UNKNOWN
}
var File_responses_proto protoreflect.FileDescriptor
var file_responses_proto_rawDesc = []byte{
0x0a, 0x0f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x12, 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x1a, 0x0e, 0x73, 0x65,
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x13, 0x63, 0x6f,
0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x22, 0x2d, 0x0a, 0x11, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x4e, 0x65, 0x77, 0x53,
0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73,
0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73,
0x22, 0x3c, 0x0a, 0x0a, 0x4e, 0x65, 0x77, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2e,
0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x12, 0x2e, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x53, 0x65, 0x74, 0x74,
0x69, 0x6e, 0x67, 0x73, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x45,
0x0a, 0x13, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20,
0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52,
0x04, 0x74, 0x79, 0x70, 0x65, 0x42, 0x0e, 0x5a, 0x0c, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x62,
0x69, 0x6e, 0x61, 0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_responses_proto_rawDescOnce sync.Once
file_responses_proto_rawDescData = file_responses_proto_rawDesc
)
func file_responses_proto_rawDescGZIP() []byte {
file_responses_proto_rawDescOnce.Do(func() {
file_responses_proto_rawDescData = protoimpl.X.CompressGZIP(file_responses_proto_rawDescData)
})
return file_responses_proto_rawDescData
}
var file_responses_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_responses_proto_goTypes = []interface{}{
(*PrepareNewSession)(nil), // 0: responses.PrepareNewSession
(*NewSession)(nil), // 1: responses.NewSession
(*SendMessageResponse)(nil), // 2: responses.SendMessageResponse
(*Settings)(nil), // 3: settings.Settings
(MessageType)(0), // 4: conversations.MessageType
}
var file_responses_proto_depIdxs = []int32{
3, // 0: responses.NewSession.settings:type_name -> settings.Settings
4, // 1: responses.SendMessageResponse.type:type_name -> conversations.MessageType
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_responses_proto_init() }
func file_responses_proto_init() {
if File_responses_proto != nil {
return
}
file_settings_proto_init()
file_conversations_proto_init()
if !protoimpl.UnsafeEnabled {
file_responses_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*PrepareNewSession); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_responses_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*NewSession); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_responses_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SendMessageResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_responses_proto_rawDesc,
NumEnums: 0,
NumMessages: 3,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_responses_proto_goTypes,
DependencyIndexes: file_responses_proto_depIdxs,
MessageInfos: file_responses_proto_msgTypes,
}.Build()
File_responses_proto = out.File
file_responses_proto_rawDesc = nil
file_responses_proto_goTypes = nil
file_responses_proto_depIdxs = nil
}

1016
libgm/binary/settings.pb.go Normal file

File diff suppressed because it is too large Load diff

12
libgm/bugle_service.go Normal file
View file

@ -0,0 +1,12 @@
package textgapi
import "go.mau.fi/mautrix-gmessages/libgm/binary"
func (c *Client) handleBugleOpCode(bugleData *binary.BugleBackendService) {
switch bugleData.Data.Type {
case 2:
c.Logger.Info().Any("type", bugleData.Data.Type).Msg("Updated sessionId to " + c.sessionHandler.sessionId + " due to BROWSER_ACTIVE alert")
case 6:
c.Logger.Info().Any("type", bugleData.Data.Type).Msg("USER_ALERT:BATTERY") // tf ?
}
}

71
libgm/builders/tenor.go Normal file
View file

@ -0,0 +1,71 @@
package builders
import (
"fmt"
"net/url"
"go.mau.fi/mautrix-gmessages/libgm/util"
)
type TenorSearch struct {
query string
locale string
content_filter string
media_filter string
limit string // limit results
}
func NewTenorSearchBuilder() *TenorSearch {
return &TenorSearch{}
}
func (t *TenorSearch) SetQuery(query string) *TenorSearch {
t.query = query
return t
}
func (t *TenorSearch) SetLocale(locale string) *TenorSearch {
t.locale = locale
return t
}
func (t *TenorSearch) SetContentFilter(content_filter string) *TenorSearch {
t.content_filter = content_filter
return t
}
func (t *TenorSearch) SetMediaFilter(media_filter string) *TenorSearch {
t.media_filter = media_filter
return t
}
func (t *TenorSearch) SetLimit(limit string) *TenorSearch {
t.limit = limit
return t
}
func (t *TenorSearch) Build() (string, error) {
if t.query == "" {
return "", fmt.Errorf("failed to build TenorSearch: query is empty")
}
params := url.Values{}
params.Add("key", util.TENOR_API_KEY)
params.Add("q", t.query)
if t.locale == "" {
t.locale = "en-US"
}
params.Add("locale", t.locale)
if t.content_filter == "" {
t.content_filter = "medium"
}
params.Add("contentfilter", t.content_filter)
if t.media_filter == "" {
t.media_filter = "minimal"
}
params.Add("media_filter", t.media_filter)
if t.limit == "" {
t.limit = "16"
}
params.Add("limit", t.limit)
return "?" + params.Encode(), nil
}

66
libgm/cache/cache.go vendored Normal file
View file

@ -0,0 +1,66 @@
package cache
import (
"encoding/json"
"fmt"
"log"
"os"
"strconv"
"go.mau.fi/mautrix-gmessages/libgm/binary"
)
type Cache struct {
Conversations Conversations `json:"conversations"`
Settings Settings `json:"sim,omitempty"`
}
func LoadCache(path string) Cache {
data, readErr := os.ReadFile(path)
if readErr != nil {
log.Fatal(readErr)
}
var cache Cache
err := json.Unmarshal(data, &cache)
if err != nil {
log.Fatal(err)
}
return cache
}
func (c *Cache) OrderMapToInterface() map[string]interface{} {
convIdMapStringInterface := make(map[string]interface{})
for key, value := range c.Conversations.Order {
convIdMapStringInterface[strconv.Itoa(key)] = value
}
return convIdMapStringInterface
}
func (c *Cache) SetSettings(settings *binary.Settings) {
c.Settings = Settings{
CarrierName: settings.Data.SimData.CarrierName,
HexHash: settings.Data.SimData.HexHash,
Version: settings.Version,
}
}
func (c *Cache) SetMessages(messages *binary.FetchMessagesResponse) {
for _, msg := range messages.Messages {
convo, ok := c.Conversations.Conversations[msg.ConversationId]
if !ok {
// handle error, such as creating a new conversation or returning
fmt.Printf("Could not find conversation with id %s", msg.ConversationId)
return
} else {
convo.UpdateMessage(msg)
}
}
}
func (c *Cache) SetConversations(conversations *binary.Conversations) {
for order, conv := range conversations.Conversations {
convertedConv := NewConversation(c, conv)
c.Conversations.Order[order] = conv.ConversationId
c.Conversations.Conversations[conv.ConversationId] = convertedConv
}
}

290
libgm/cache/conversation.go vendored Normal file
View file

@ -0,0 +1,290 @@
package cache
import (
"fmt"
"log"
"sort"
"go.mau.fi/mautrix-gmessages/libgm/binary"
)
type SmallInfo struct {
Type int64 `json:"type,omitempty"`
Number string `json:"number,omitempty"`
ParticipantId string `json:"participantId,omitempty"`
}
type Participant struct {
SmallInfo *SmallInfo `json:"smallInfo,omitempty"`
HexHash string `json:"hexHash,omitempty"`
IsMe bool `json:"isMe,omitempty"`
Bs int64 `json:"bs,omitempty"`
DisplayName string `json:"displayName,omitempty"`
}
type ImagePixels struct {
Width int64 `json:"width,omitempty"`
Height int64 `json:"height,omitempty"`
}
type ImageMessage struct {
SomeNumber int64 `json:"someNumber"`
ImageId string `json:"imageId"`
ImageName string `json:"imageName"`
Size int64 `json:"size"`
Pixels ImagePixels `json:"pixels"`
ImageBuffer []byte `json:"imageBuffer"`
DecryptionKey []byte `json:"decryptionKey"`
}
type TextMessage struct {
Content string `json:"content"`
}
type IsFromMe struct {
FromMe bool `json:"fromMe"`
}
type MessageData struct {
OrderInternal string `json:"orderInternal"`
TextData *TextMessage `json:"textData,omitempty"`
ImageData *ImageMessage `json:"imageData,omitempty"`
}
type MessageStatus struct {
Code int64 `json:"code,omitempty"`
ErrMsg string `json:"errMsg,omitempty"`
MsgType string `json:"msgType,omitempty"`
}
type Message struct {
cache *Cache
MessageId string `json:"messageId"`
From IsFromMe `json:"from"`
MessageStatus MessageStatus `json:"details"`
Timestamp int64 `json:"timestamp"`
ConvId string `json:"convId"`
ParticipantId string `json:"participantId"`
MessageData []MessageData `json:"messageData"`
MessageType string `json:"messageType"`
}
func (m *Message) FromMe() bool {
conv, _ := m.cache.Conversations.GetConversation(m.ConvId)
return m.ParticipantId == conv.SelfParticipantId
}
type LatestMessage struct {
Content string `json:"content,omitempty"`
FromMe bool `json:"fromMe,omitempty"`
DisplayName string `json:"displayName,omitempty"`
MessageId string `json:"messageId,omitempty"`
}
type Conversation struct {
cache *Cache
MessageOrder map[int]string `json:"messageOrder"`
Messages map[string]Message `json:"messages"`
ConversationId string `json:"conversationId"`
DisplayName string `json:"displayName"`
LatestMessage LatestMessage `json:"latestMessage"`
IsGroupChat bool `json:"isGroupChat,omitempty"`
Timestamp int64 `json:"timestamp"`
Status int64 `json:"status"`
HexHash string `json:"hexHash"`
Type int64 `json:"type"`
SelfParticipantId string `json:"selfParticipantId,omitempty"`
Participants []Participant `json:"participants"`
ParticipantIds []string `json:"participantIds,omitempty"` // excluded self id
}
type Conversations struct {
cache *Cache
/*
{0: "1", 1: "4"}
order -> conversationId
index 0 = first conversation in order
*/
Order map[int]string `json:"order"`
/*
Map conversations by conversationId
*/
Conversations map[string]*Conversation `json:"conversations"`
}
func (c *Conversations) SetCache(cache *Cache) {
c.cache = cache
}
func (c *Conversations) DeleteConversation(convId string) {
delete(c.Conversations, convId)
}
func (c *Conversations) UpdateConversation(conversation *binary.Conversation) *Conversation {
newConversation := NewConversation(c.cache, conversation)
c.Conversations[conversation.ConversationId] = newConversation
return newConversation
}
func (c *Conversation) GetMessage(msgId string) (Message, error) {
message, foundMsg := c.Messages[msgId]
if !foundMsg {
return Message{}, fmt.Errorf("could not find that message cached")
}
return message, nil
}
func (c *Conversation) Delete() {
c.cache.Conversations.DeleteConversation(c.ConversationId)
}
func (c *Conversation) UpdateMessage(msg *binary.Message) Message {
newMsg := NewMessage(c.cache, msg)
if c.Messages == nil {
log.Println("c.messages was nil so created new map")
c.Messages = make(map[string]Message)
}
c.Messages[msg.MessageId] = newMsg
return newMsg
}
func (c *Conversations) GetConversationByOrder(order int) (*Conversation, error) {
convId, ok := c.Order[order]
if !ok {
return &Conversation{}, fmt.Errorf("could not find a conversation that occupies that order")
}
conversation, foundConvo := c.Conversations[convId]
if !foundConvo {
return &Conversation{}, fmt.Errorf("could not find that conversation cached, oddly enough it seems to be cached in the order map though... investigate further")
}
return conversation, nil
}
func (c *Conversation) GetOrderSlice() []string {
keys := make([]string, 0, len(c.Messages))
for k := range c.Messages {
keys = append(keys, k)
}
sort.Slice(keys, func(i, j int) bool {
return c.Messages[keys[i]].Timestamp < c.Messages[keys[j]].Timestamp
})
return keys
}
func (c *Conversations) GetOrderSlice() []int {
s := make([]int, 0)
for i := range c.Order {
s = append(s, i)
}
return s
}
func (c *Conversations) GetConversation(convId string) (*Conversation, error) {
convo, ok := c.Conversations[convId]
if !ok {
// handle error, such as creating a new conversation or returning
return &Conversation{}, fmt.Errorf("could not find conversation cached")
} else {
return convo, nil
}
}
func NewConversation(cache *Cache, conv *binary.Conversation) *Conversation {
currConv, convErr := cache.Conversations.GetConversation(conv.ConversationId)
participants := ParseParticipants(conv.Participants)
newConversation := Conversation{
cache: cache,
ConversationId: conv.ConversationId,
DisplayName: conv.Name,
Timestamp: conv.TimestampMs,
Status: conv.Status,
HexHash: conv.HashHex,
Type: conv.Type,
Participants: participants,
ParticipantIds: conv.OtherParticipants,
SelfParticipantId: conv.SelfParticipantId,
}
if conv.LatestMessage != nil {
newConversation.LatestMessage = LatestMessage{
Content: conv.LatestMessage.Content,
FromMe: conv.LatestMessage.FromMe,
DisplayName: conv.LatestMessage.DisplayName,
MessageId: conv.MessageId,
}
}
if convErr == nil {
newConversation.MessageOrder = currConv.MessageOrder
newConversation.Messages = currConv.Messages
} else {
newConversation.MessageOrder = make(map[int]string)
newConversation.Messages = make(map[string]Message)
}
return &newConversation
}
func ParseParticipants(participants []*binary.Participant) []Participant {
partSlice := make([]Participant, 0)
for _, p := range participants {
partSlice = append(partSlice, Participant{
SmallInfo: &SmallInfo{
Type: p.SmallInfo.Type,
Number: p.SmallInfo.Number,
ParticipantId: p.SmallInfo.ParticipantId,
},
HexHash: p.HashHex,
IsMe: p.IsMe,
Bs: p.Bs,
DisplayName: p.DisplayName,
})
}
return partSlice
}
func NewMessage(cache *Cache, message *binary.Message) Message {
msg := Message{
cache: cache,
MessageId: message.MessageId,
ConvId: message.ConversationId,
From: IsFromMe{
FromMe: message.From.FromMe,
},
Timestamp: message.Timestamp,
ParticipantId: message.ParticipantId,
MessageType: message.Type.String(),
MessageStatus: MessageStatus{
Code: message.MessageStatus.Code,
ErrMsg: message.MessageStatus.ErrMsg,
MsgType: message.MessageStatus.MsgStatus,
},
MessageData: make([]MessageData, 0),
}
for _, data := range message.MessageInfo {
msgData := MessageData{
OrderInternal: data.OrderInternal,
}
switch d := data.Data.(type) {
case *binary.MessageInfo_ImageContent:
msgData.ImageData = &ImageMessage{
SomeNumber: d.ImageContent.SomeNumber,
ImageId: d.ImageContent.ImageId,
ImageName: d.ImageContent.ImageName,
Size: d.ImageContent.Size,
Pixels: ImagePixels{Width: d.ImageContent.Pixels.Width, Height: d.ImageContent.Pixels.Height},
ImageBuffer: d.ImageContent.ImageData,
DecryptionKey: d.ImageContent.DecryptionKey,
}
case *binary.MessageInfo_MessageContent:
msgData.TextData = &TextMessage{
Content: d.MessageContent.Content,
}
}
msg.MessageData = append(msg.MessageData, msgData)
}
return msg
}

8
libgm/cache/settings.go vendored Normal file
View file

@ -0,0 +1,8 @@
package cache
type Settings struct {
CarrierName string `json:"carrierName,omitempty"`
HexHash string `json:"hexHash,omitempty"`
Version string `json:"version,omitempty"`
}

242
libgm/client.go Normal file
View file

@ -0,0 +1,242 @@
package textgapi
import (
"encoding/json"
"io"
"log"
"net/http"
"net/url"
"os"
"time"
"github.com/rs/zerolog"
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/cache"
"go.mau.fi/mautrix-gmessages/libgm/crypto"
"go.mau.fi/mautrix-gmessages/libgm/payload"
"go.mau.fi/mautrix-gmessages/libgm/util"
)
type DevicePair struct {
Mobile *binary.Device
Browser *binary.Device
}
type Proxy func(*http.Request) (*url.URL, error)
type EventHandler func(evt interface{})
type Client struct {
Logger zerolog.Logger
Conversations *Conversations
Session *Session
rpc *RPC
devicePair *DevicePair
pairer *Pairer
cryptor *crypto.Cryptor
imageCryptor *crypto.ImageCryptor
evHandler EventHandler
sessionHandler *SessionHandler
instructions *Instructions
rpcKey string
ttl int64
proxy Proxy
http *http.Client
cache cache.Cache
}
func NewClient(devicePair *DevicePair, cryptor *crypto.Cryptor, logger zerolog.Logger, proxy *string) *Client {
sessionHandler := &SessionHandler{
requests: make(map[string]map[int64]*ResponseChan),
responseTimeout: time.Duration(5000) * time.Millisecond,
}
if cryptor == nil {
cryptor = crypto.NewCryptor(nil, nil)
}
cli := &Client{
Logger: logger,
devicePair: devicePair,
sessionHandler: sessionHandler,
cryptor: cryptor,
imageCryptor: &crypto.ImageCryptor{},
http: &http.Client{},
cache: cache.Cache{},
}
sessionHandler.client = cli
cli.instructions = NewInstructions(cli.cryptor)
if proxy != nil {
cli.SetProxy(*proxy)
}
rpc := &RPC{client: cli, http: &http.Client{Transport: &http.Transport{Proxy: cli.proxy}}}
cli.rpc = rpc
cli.Logger.Debug().Any("data", cryptor).Msg("Cryptor")
cli.cache.Conversations = cache.Conversations{
Conversations: make(map[string]*cache.Conversation),
Order: make(map[int]string),
}
cli.cache.Conversations.SetCache(&cli.cache)
cli.setApiMethods()
return cli
}
func (c *Client) SetEventHandler(eventHandler EventHandler) {
c.evHandler = eventHandler
}
func (c *Client) SetProxy(proxy string) error {
proxyParsed, err := url.Parse(proxy)
if err != nil {
c.Logger.Fatal().Err(err).Msg("Failed to set proxy")
}
proxyUrl := http.ProxyURL(proxyParsed)
c.http.Transport = &http.Transport{
Proxy: proxyUrl,
}
c.proxy = proxyUrl
c.Logger.Debug().Any("proxy", proxyParsed.Host).Msg("SetProxy")
return nil
}
func (c *Client) Connect(rpcKey string) error {
rpcPayload, receiveMesageSessionId, err := payload.ReceiveMessages(rpcKey)
if err != nil {
log.Fatal(err)
return err
}
c.rpc.rpcSessionId = receiveMesageSessionId
c.rpcKey = rpcKey
c.rpc.ListenReceiveMessages(rpcPayload)
c.Logger.Debug().Any("rpcKey", rpcKey).Msg("Successfully connected to server")
return nil
}
func (c *Client) Reconnect(rpcKey string) error {
c.rpc.CloseConnection()
for c.rpc.conn != nil {
time.Sleep(time.Millisecond * 100)
}
err := c.Connect(rpcKey)
if err != nil {
c.Logger.Err(err).Any("rpcKey", rpcKey).Msg("Failed to reconnect")
return err
}
c.Logger.Debug().Any("rpcKey", rpcKey).Msg("Successfully reconnected to server")
sendInitialDataErr := c.rpc.sendInitialData()
if sendInitialDataErr != nil {
log.Fatal(sendInitialDataErr)
}
return nil
}
func (c *Client) triggerEvent(evt interface{}) {
if c.evHandler != nil {
c.evHandler(evt)
}
}
func (c *Client) setApiMethods() {
c.Conversations = &Conversations{
client: c,
openConversation: openConversation{
client: c,
},
fetchConversationMessages: fetchConversationMessages{
client: c,
},
}
c.Session = &Session{
client: c,
prepareNewSession: prepareNewSession{
client: c,
},
newSession: newSession{
client: c,
},
}
}
func (c *Client) decryptImages(messages *binary.FetchMessagesResponse) error {
for _, msg := range messages.Messages {
switch msg.GetType() {
case *binary.MessageType_IMAGE.Enum():
for _, details := range msg.GetMessageInfo() {
switch data := details.GetData().(type) {
case *binary.MessageInfo_ImageContent:
decryptedImageData, err := c.decryptImageData(data.ImageContent.ImageId, data.ImageContent.DecryptionKey)
if err != nil {
log.Fatal(err)
return err
}
data.ImageContent.ImageData = decryptedImageData
}
}
}
}
return nil
}
func (c *Client) decryptImageData(imageId string, key []byte) ([]byte, error) {
decodedRpcKey, err := crypto.Base64DecodeStandard(c.rpcKey)
if err != nil {
return nil, err
}
reqId := util.RandomUUIDv4()
download_metadata := &binary.UploadImagePayload{
MetaData: &binary.ImageMetaData{
ImageId: imageId,
Encrypted: true,
},
AuthData: &binary.AuthMessageBytes{
RequestId: reqId,
RpcKey: decodedRpcKey,
Date: &binary.Date{
Year: 2023,
Seq1: 6,
Seq2: 8,
Seq3: 4,
Seq4: 6,
},
},
}
download_metadata_bytes, err2 := binary.EncodeProtoMessage(download_metadata)
if err2 != nil {
return nil, err2
}
download_metadata_b64 := crypto.EncodeBase64Standard(download_metadata_bytes)
req, err := http.NewRequest("GET", util.UPLOAD_MEDIA, nil)
if err != nil {
return nil, err
}
util.BuildUploadHeaders(req, download_metadata_b64)
res, reqErr := c.http.Do(req)
if reqErr != nil {
return nil, reqErr
}
c.Logger.Info().Any("url", util.UPLOAD_MEDIA).Any("headers", res.Request.Header).Msg("Decrypt Image Headers")
defer res.Body.Close()
encryptedBuffImg, err3 := io.ReadAll(res.Body)
if err3 != nil {
return nil, err3
}
c.Logger.Debug().Any("key", key).Any("encryptedLength", len(encryptedBuffImg)).Msg("Attempting to decrypt image")
c.imageCryptor.UpdateDecryptionKey(key)
decryptedImageBytes, decryptionErr := c.imageCryptor.DecryptData(encryptedBuffImg)
if decryptionErr != nil {
log.Println("Error:", decryptionErr)
return nil, decryptionErr
}
return decryptedImageBytes, nil
}
func (c *Client) SaveCache(path string) {
toSaveJson, jsonErr := json.Marshal(c.cache)
if jsonErr != nil {
log.Fatal(jsonErr)
}
os.WriteFile(path, toSaveJson, os.ModePerm)
}
func (c *Client) GetCache() cache.Cache {
return c.cache
}

33
libgm/command_handler.go Normal file
View file

@ -0,0 +1,33 @@
package textgapi
import (
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/util"
)
func (c *Client) processSessionResponse(prepareSession []*Response, newSession []*Response) (*util.SessionResponse, error) {
prepDecoded, prepDecodeErr := prepareSession[0].decryptData()
if prepDecodeErr != nil {
return nil, prepDecodeErr
}
sessDecoded, sessDecodeErr := newSession[0].decryptData()
if sessDecodeErr != nil {
return nil, sessDecodeErr
}
sess := sessDecoded.(*binary.NewSession)
prep := prepDecoded.(*binary.PrepareNewSession)
return &util.SessionResponse{
Success: prep.Success,
Settings: sess.Settings,
}, nil
}
func (c *Client) processFetchMessagesResponse(fetchMessagesRes []*Response, openConversationRes []*Response, setActiveConversationRes []*Response) (*binary.FetchMessagesResponse, error) {
messagesDecoded, messagesDecodeErr := fetchMessagesRes[0].decryptData()
if messagesDecodeErr != nil {
return nil, messagesDecodeErr
}
return messagesDecoded.(*binary.FetchMessagesResponse), nil
}

208
libgm/conversations.go Normal file
View file

@ -0,0 +1,208 @@
package textgapi
import (
"fmt"
"log"
"go.mau.fi/mautrix-gmessages/libgm/binary"
)
type Conversations struct {
client *Client
watching string // current open conversation
openConversation openConversation
fetchConversationMessages fetchConversationMessages
}
func (c *Conversations) List(count int64) (*binary.Conversations, error) {
encryptedProtoPayload := &binary.ListCoversationsPayload{Count: count, Field4: 1}
instruction, _ := c.client.instructions.GetInstruction(LIST_CONVERSATIONS)
sentRequestId, _ := c.client.createAndSendRequest(instruction.Opcode, c.client.ttl, false, encryptedProtoPayload.ProtoReflect())
responses, err := c.client.sessionHandler.WaitForResponse(sentRequestId, instruction.Opcode)
if err != nil {
return nil, err
}
decryptedProto, decryptErr := responses[0].decryptData()
if decryptErr != nil {
return nil, decryptErr
}
if decryptedData, ok := decryptedProto.(*binary.Conversations); ok {
c.client.cache.SetConversations(decryptedData)
return decryptedData, nil
} else {
return nil, fmt.Errorf("failed to assert decryptedProto into type Conversations")
}
}
func (c *Conversations) SendMessage(messageBuilder *MessageBuilder) (*binary.SendMessageResponse, error) {
conv, notFound := c.client.cache.Conversations.GetConversation(messageBuilder.GetConversationId())
if notFound != nil {
log.Fatal(notFound)
}
hasSelfParticipantId := messageBuilder.GetSelfParticipantId()
if hasSelfParticipantId == "" {
messageBuilder.SetSelfParticipantId(conv.SelfParticipantId)
}
encryptedProtoPayload, failedToBuild := messageBuilder.Build()
if failedToBuild != nil {
log.Fatal(failedToBuild)
}
instruction, _ := c.client.instructions.GetInstruction(SEND_TEXT_MESSAGE)
c.client.Logger.Debug().Any("payload", encryptedProtoPayload).Msg("SendMessage Payload")
sentRequestId, _ := c.client.createAndSendRequest(instruction.Opcode, c.client.ttl, false, encryptedProtoPayload.ProtoReflect())
responses, err := c.client.sessionHandler.WaitForResponse(sentRequestId, instruction.Opcode)
if err != nil {
log.Fatal(err)
return nil, err
}
decryptedProto, decryptErr := responses[0].decryptData()
if decryptErr != nil {
return nil, decryptErr
}
if decryptedData, ok := decryptedProto.(*binary.SendMessageResponse); ok {
return decryptedData, nil
} else {
return nil, fmt.Errorf("failed to assert decryptedProto into type SendMessageResponse")
}
}
func (c *Conversations) FetchMessages(convId string, count int64, cursor *binary.Cursor) (*binary.FetchMessagesResponse, error) {
var openConversationRes []*Response
var openConversationErr error
if c.watching != convId {
openConversationRes, openConversationErr = c.openConversation.Execute(convId)
if openConversationErr != nil {
return nil, openConversationErr
}
c.watching = convId
}
fetchMessagesRes, fetchMessagesErr := c.fetchConversationMessages.Execute(convId, count, cursor)
if fetchMessagesErr != nil {
return nil, fetchMessagesErr
}
fetchedMessagesResponse, processFail := c.client.processFetchMessagesResponse(fetchMessagesRes, openConversationRes, nil)
if processFail != nil {
return nil, processFail
}
c.client.cache.SetMessages(fetchedMessagesResponse)
return fetchedMessagesResponse, nil
}
type fetchConversationMessages struct {
client *Client
}
func (f *fetchConversationMessages) Execute(convId string, count int64, cursor *binary.Cursor) ([]*Response, error) {
encryptedProtoPayload := &binary.FetchConversationMessagesPayload{ConversationId: convId, Count: count, Cursor: cursor}
instruction, _ := f.client.instructions.GetInstruction(FETCH_MESSAGES_CONVERSATION)
sentRequestId, _ := f.client.createAndSendRequest(instruction.Opcode, f.client.ttl, false, encryptedProtoPayload.ProtoReflect())
responses, err := f.client.sessionHandler.WaitForResponse(sentRequestId, instruction.Opcode)
if err != nil {
return nil, err
}
return responses, nil
}
type openConversation struct {
client *Client
}
func (o *openConversation) Execute(convId string) ([]*Response, error) {
encryptedProtoPayload := &binary.OpenConversationPayload{ConversationId: convId}
instruction, _ := o.client.instructions.GetInstruction(OPEN_CONVERSATION)
sentRequestId, _ := o.client.createAndSendRequest(instruction.Opcode, o.client.ttl, false, encryptedProtoPayload.ProtoReflect())
responses, err := o.client.sessionHandler.WaitForResponse(sentRequestId, instruction.Opcode)
if err != nil {
return nil, err
}
// Rest of the processing...
return responses, nil
}
/*
func (c *Conversations) SendMessage(conversationId string, content string, participantCount string) (*binary.SendMessageResponse, error) {
encryptedProtoPayload := payload.NewSendConversationTextMessage(conversationId, content, participantCount)
sentRequestId, _ := c.client.createAndSendRequest(3, c.client.ttl, false, encryptedProtoPayload.ProtoReflect())
c.client.Logger.Debug().Any("requestId", sentRequestId).Msg("Sent sendmessage request.")
response, responseErr := c.client.sessionHandler.WaitForResponse(sentRequestId, 3)
if responseErr != nil {
c.client.Logger.Err(responseErr).Msg("SendMessage channel response error")
return nil, responseErr
} else {
decryptedProto, decryptErr := response.decryptData()
if decryptErr != nil {
return nil, decryptErr
}
if decryptedData, ok := decryptedProto.(*binary.SendMessageResponse); ok {
return decryptedData, nil
} else {
return nil, fmt.Errorf("failed to assert decryptedProto into type SendMessageResponse")
}
}
}
func (c *Conversations) PrepareOpen() (interface{}, error) {
encryptedProtoPayload := &binary.PrepareOpenConversationPayload{Field2:1}
sentRequestId, _ := c.client.createAndSendRequest(22, c.client.ttl, false, encryptedProtoPayload.ProtoReflect())
c.client.Logger.Debug().Any("requestId", sentRequestId).Msg("Sent PrepareOpenConversation request.")
response, responseErr := c.client.sessionHandler.WaitForResponse(sentRequestId, 22)
if responseErr != nil {
c.client.Logger.Err(responseErr).Msg("PrepareOpenConversation channel response error")
return nil, responseErr
} else {
c.client.Logger.Info().Any("response", response).Msg("PrepareOpenConversation response data")
}
return nil, nil
}
func (c *Conversations) Open(conversationId string) (interface{}, error) {
encryptedProtoPayload := &binary.OpenConversationPayload{ConversationId:conversationId}
sentRequestId, _ := c.client.createAndSendRequest(21, c.client.ttl, false, encryptedProtoPayload.ProtoReflect())
c.client.Logger.Debug().Any("requestId", sentRequestId).Msg("Sent OpenConversation request.")
response, responseErr := c.client.sessionHandler.WaitForResponse(sentRequestId, 21)
if responseErr != nil {
c.client.Logger.Err(responseErr).Msg("OpenConversation channel response error")
return nil, responseErr
} else {
c.client.Logger.Info().Any("response", response).Msg("OpenConversation response data")
}
return nil, nil
}
func (c *Conversations) FetchMessages(conversationId string, count int64) (*binary.FetchMessagesResponse, error) {
encryptedProtoPayload := &binary.FetchConversationMessagesPayload{ConversationId:conversationId,Count:count}
sentRequestId, _ := c.client.createAndSendRequest(2, c.client.ttl, false, encryptedProtoPayload.ProtoReflect())
c.client.Logger.Debug().Any("requestId", sentRequestId).Msg("Sent FetchMessages request.")
response, responseErr := c.client.sessionHandler.WaitForResponse(sentRequestId, 2)
if responseErr != nil {
c.client.Logger.Err(responseErr).Msg("FetchMessages channel response error")
return nil, responseErr
} else {
decryptedMessages, decryptedErr := c.client.newMessagesResponse(response)
if decryptedErr != nil {
return nil, decryptedErr
}
return decryptedMessages, nil
}
}
*/

41
libgm/crypto/B64.go Normal file
View file

@ -0,0 +1,41 @@
package crypto
import (
"encoding/base64"
"fmt"
"strings"
)
func EncodeBase64Standard(data []byte) string {
return base64.StdEncoding.EncodeToString(data)
}
func EncodeBase64(data []byte) string {
return base64.RawURLEncoding.EncodeToString(data)
}
func Base64Decode(input string) ([]byte, error) {
padding := len(input) % 4
if padding > 0 {
input += strings.Repeat("=", 4-padding)
}
data, err := base64.URLEncoding.DecodeString(input)
if err != nil {
return nil, err
}
return data, nil
}
func Base64DecodeStandard(input string) ([]byte, error) {
decoded, err := base64.StdEncoding.DecodeString(input)
if err != nil {
fmt.Println("decode error:", err)
return nil, err
}
return decoded, nil
}
func Base64Encode(input []byte) string {
return base64.StdEncoding.EncodeToString(input)
}

113
libgm/crypto/ECDSA.go Normal file
View file

@ -0,0 +1,113 @@
package crypto
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"encoding/base64"
"encoding/json"
"fmt"
"math/big"
)
type JWK struct {
Kty string `json:"kty"`
Crv string `json:"crv"`
D string `json:"d"`
X string `json:"x"`
Y string `json:"y"`
Ext bool `json:"ext"`
KeyOps []string `json:"key_ops"`
PrivateBytes []byte `json:"privateBytes,omitempty"`
}
// Returns a byte slice containing the JWK and an error if the generation or export failed.
func (t *JWK) Marshal() ([]byte, error) {
JWKJSON, err := json.Marshal(t)
if err != nil {
fmt.Printf("Failed to marshal JWK: %v", err)
return nil,err
}
fmt.Printf("%s\n", JWKJSON)
return JWKJSON,err
}
func (t *JWK) PrivKeyB64Bytes() ([]byte, error){
decodedPrivateKey, err2 := Base64Decode(t.D)
return decodedPrivateKey, err2
}
func (t *JWK) ExtractPublicKeyDetails(pubKey []byte) *JWK {
x := EncodeBase64(pubKey[1:33])
y := EncodeBase64(pubKey[33:])
return &JWK{
Kty: "EC",
Crv: "P-256",
X: x,
Y: y,
}
}
func (t *JWK) DecompressPubkey() (*ecdsa.PublicKey, error) {
xBytes, err := base64.RawURLEncoding.DecodeString(t.X)
if err != nil {
return nil, err
}
yBytes, err := base64.RawURLEncoding.DecodeString(t.Y)
if err != nil {
return nil, err
}
x := new(big.Int).SetBytes(xBytes)
y := new(big.Int).SetBytes(yBytes)
pubKey := &ecdsa.PublicKey{
Curve: elliptic.P256(),
X: x,
Y: y,
}
return pubKey, nil
}
func (t *JWK) UncompressPubKey() ([]byte, error) {
xBytes, err := base64.RawURLEncoding.DecodeString(t.X)
if err != nil {
return nil, err
}
yBytes, err := base64.RawURLEncoding.DecodeString(t.Y)
if err != nil {
return nil, err
}
x := new(big.Int).SetBytes(xBytes)
y := new(big.Int).SetBytes(yBytes)
pubKey := &ecdsa.PublicKey{
Curve: elliptic.P256(),
X: x,
Y: y,
}
uncompressedPubKey := elliptic.Marshal(pubKey.Curve, pubKey.X, pubKey.Y)
return uncompressedPubKey, nil
}
// GenerateECDSA_P256_JWK generates a new ECDSA private key with P-256 curve
func GenerateECDSA_P256_JWK() (*JWK, error) {
privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
fmt.Printf("Failed to generate private key: %v", err)
return nil,err
}
JWK := &JWK{
Kty: "EC",
Crv: "P-256",
D: base64.RawURLEncoding.EncodeToString(privKey.D.Bytes()),
X: base64.RawURLEncoding.EncodeToString(privKey.X.Bytes()),
Y: base64.RawURLEncoding.EncodeToString(privKey.Y.Bytes()),
Ext: true,
KeyOps: []string{"sign"},
}
return JWK,nil
}

115
libgm/crypto/cryptor.go Normal file
View file

@ -0,0 +1,115 @@
package crypto
import (
"crypto/aes"
"crypto/cipher"
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"encoding/json"
"errors"
"io"
"os"
"google.golang.org/protobuf/reflect/protoreflect"
"go.mau.fi/mautrix-gmessages/libgm/binary"
)
type Cryptor struct {
AES_CTR_KEY_256, SHA_256_KEY []byte
}
func NewCryptor(aes_key []byte, sha_key []byte) *Cryptor {
if aes_key != nil && sha_key != nil {
return &Cryptor{
AES_CTR_KEY_256: aes_key,
SHA_256_KEY: sha_key,
}
}
aes_key, sha_key = GenerateKeys()
return &Cryptor{
AES_CTR_KEY_256: aes_key,
SHA_256_KEY: sha_key,
}
}
func (c *Cryptor) SaveAsJson() {
AES_B64, SHA_B64 := EncodeBase64Standard(c.AES_CTR_KEY_256), EncodeBase64Standard(c.SHA_256_KEY)
inter := struct {
AES_CTR_KEY_256 string
SHA_256_KEY string
}{
AES_CTR_KEY_256: AES_B64,
SHA_256_KEY: SHA_B64,
}
jsonData, _ := json.Marshal(inter)
os.WriteFile("cryptor.json", jsonData, os.ModePerm)
}
func (c *Cryptor) Encrypt(plaintext []byte) ([]byte, error) {
iv := make([]byte, aes.BlockSize)
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err
}
block, err := aes.NewCipher(c.AES_CTR_KEY_256)
if err != nil {
return nil, err
}
ciphertext := make([]byte, len(plaintext))
stream := cipher.NewCTR(block, iv)
stream.XORKeyStream(ciphertext, plaintext)
ciphertext = append(ciphertext, iv...)
mac := hmac.New(sha256.New, c.SHA_256_KEY)
mac.Write(ciphertext)
hmac := mac.Sum(nil)
ciphertext = append(ciphertext, hmac...)
return ciphertext, nil
}
func (c *Cryptor) Decrypt(encryptedData []byte) ([]byte, error) {
if len(encryptedData) < 48 {
return nil, errors.New("input data is too short")
}
hmacSignature := encryptedData[len(encryptedData)-32:]
encryptedDataWithoutHMAC := encryptedData[:len(encryptedData)-32]
mac := hmac.New(sha256.New, c.SHA_256_KEY)
mac.Write(encryptedDataWithoutHMAC)
expectedHMAC := mac.Sum(nil)
if !hmac.Equal(hmacSignature, expectedHMAC) {
return nil, errors.New("HMAC mismatch")
}
iv := encryptedDataWithoutHMAC[len(encryptedDataWithoutHMAC)-16:]
encryptedDataWithoutHMAC = encryptedDataWithoutHMAC[:len(encryptedDataWithoutHMAC)-16]
block, err := aes.NewCipher(c.AES_CTR_KEY_256)
if err != nil {
return nil, err
}
stream := cipher.NewCTR(block, iv)
stream.XORKeyStream(encryptedDataWithoutHMAC, encryptedDataWithoutHMAC)
return encryptedDataWithoutHMAC, nil
}
func (c *Cryptor) DecryptAndDecodeData(encryptedData []byte, message protoreflect.ProtoMessage) error {
decryptedData, err := c.Decrypt(encryptedData)
if err != nil {
return err
}
err = binary.DecodeProtoMessage(decryptedData, message)
if err != nil {
return err
}
return nil
}

32
libgm/crypto/decode.go Normal file
View file

@ -0,0 +1,32 @@
package crypto
import (
"google.golang.org/protobuf/proto"
"go.mau.fi/mautrix-gmessages/libgm/binary"
)
func DecodeAndEncodeB64(data string, msg proto.Message) error {
decodedBytes, err := Base64DecodeStandard(data)
if err != nil {
return err
}
err = binary.DecodeProtoMessage(decodedBytes, msg)
if err != nil {
return err
}
return nil
}
func DecodeEncodedResponse(data string) (*binary.EncodedResponse, error) {
decodedBytes, err := Base64DecodeStandard(data)
if err != nil {
return nil, err
}
decodedData := &binary.EncodedResponse{}
err = binary.DecodeProtoMessage(decodedBytes, decodedData)
if err != nil {
return nil, err
}
return decodedData, nil
}

60
libgm/crypto/encode.go Normal file
View file

@ -0,0 +1,60 @@
package crypto
import (
"google.golang.org/protobuf/proto"
"go.mau.fi/mautrix-gmessages/libgm/binary"
)
var SequenceOne = []int{1, 2, 840, 10045, 2, 1}
var SequenceTwo = []int{1, 2, 840, 10045, 3, 1, 7}
func EncodeValues(a *[]byte, b []int) {
*a = append(*a, 6)
idx := len(*a)
*a = append(*a, 0)
*a = append(*a, byte(40*b[0]+b[1]))
for i := 2; i < len(b); i++ {
d := b[i]
e := make([]byte, 0)
if d > 128 {
e = append(e, byte(d/128)+128)
}
e = append(e, byte(d%128))
*a = append(*a, e...)
}
(*a)[idx] = byte(len(*a) - idx - 1)
}
func AppendBytes(a []byte, b []byte) []byte {
newA := make([]byte, len(a))
copy(newA, a)
newA = HelperAppendBytes(newA, 48)
newA = HelperAppendBytes(newA, byte(len(b)))
for _, value := range b {
newA = HelperAppendBytes(newA, value)
}
return newA
}
func HelperAppendBytes(a []byte, b byte) []byte {
return append(a, b)
}
func AppendByteSequence(byteArr1 []byte, byteArr2 []byte, uncompressedPublicKey []byte) []byte {
copiedByteArray := AppendBytes(byteArr1, byteArr2)
copiedByteArray = HelperAppendBytes(copiedByteArray, 3)
copiedByteArray = HelperAppendBytes(copiedByteArray, uint8(len(uncompressedPublicKey)+1))
copiedByteArray = HelperAppendBytes(copiedByteArray, 0)
return copiedByteArray
}
func EncodeProtoB64(message proto.Message) (string, error) {
protoBytes, protoErr := binary.EncodeProtoMessage(message)
if protoErr != nil {
return "", protoErr
}
encodedStr := EncodeBase64Standard(protoBytes)
return encodedStr, nil
}

27
libgm/crypto/generate.go Normal file
View file

@ -0,0 +1,27 @@
package crypto
import (
"crypto/rand"
"log"
)
func GenerateKey(length int) ([]byte, error) {
key := make([]byte, length)
_, err := rand.Read(key)
if err != nil {
return nil, err
}
return key, nil
}
func GenerateKeys() ([]byte, []byte) {
key, err := GenerateKey(32)
if err != nil {
log.Fatal(err)
}
key2, err2 := GenerateKey(32)
if err2 != nil {
log.Fatal(err2)
}
return key, key2
}

View file

@ -0,0 +1,194 @@
package crypto
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"fmt"
"math"
)
type ImageCryptor struct {
key []byte
}
func NewImageCryptor(key []byte) (*ImageCryptor, error) {
if len(key) != 32 {
return nil, fmt.Errorf("unsupported AES key length (got=%d expected=32)", len(key))
}
return &ImageCryptor{key: key}, nil
}
func (ic *ImageCryptor) GetKey() []byte {
return ic.key
}
func (ic *ImageCryptor) UpdateDecryptionKey(key []byte) {
ic.key = key
}
func (ic *ImageCryptor) Encrypt(imageBytes []byte, aad []byte) ([]byte, error) {
block, err := aes.NewCipher(ic.key)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
nonce := make([]byte, gcm.NonceSize())
_, err = rand.Read(nonce)
if err != nil {
return nil, err
}
ciphertext := gcm.Seal(nonce, nonce, imageBytes, aad)
return ciphertext, nil
}
func (ic *ImageCryptor) Decrypt(iv []byte, data []byte, aad []byte) ([]byte, error) {
block, err := aes.NewCipher(ic.key)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
if len(data) < gcm.NonceSize() {
return nil, fmt.Errorf("invalid encrypted data length (got=%d)", len(data))
}
ciphertext := data[gcm.NonceSize():]
decrypted, err := gcm.Open(nil, iv, ciphertext, aad)
if err != nil {
return nil, err
}
return decrypted, nil
}
func (ic *ImageCryptor) EncryptData(data []byte) ([]byte, error) {
rawChunkSize := 1 << 15
chunkSize := rawChunkSize-28
var tasks []chan []byte
chunkIndex := 0
for i := 0; i < len(data); i += chunkSize {
if i+chunkSize > len(data) {
chunkSize = len(data) - i
}
chunk := make([]byte, chunkSize)
copy(chunk, data[i:i+chunkSize])
aad := ic.calculateAAD(chunkIndex, i+chunkSize, len(data))
tasks = append(tasks, make(chan []byte))
go func(chunk, aad []byte, task chan []byte) {
encrypted, err := ic.Encrypt(chunk, aad)
if err != nil {
fmt.Println(err)
task <- nil
} else {
task <- encrypted
}
}(chunk, aad, tasks[chunkIndex])
chunkIndex++
}
var result [][]byte
for _, task := range tasks {
encrypted := <-task
if encrypted == nil {
continue
}
result = append(result, encrypted)
}
var concatted []byte
for _, r := range result {
concatted = append(concatted, r...)
}
encryptedHeader := []byte{0, byte(math.Log2(float64(rawChunkSize)))}
return append(encryptedHeader, concatted...), nil
}
func (ic *ImageCryptor) DecryptData(encryptedData []byte) ([]byte, error) {
if len(encryptedData) == 0 || len(ic.key) != 32 {
return encryptedData, nil
}
if encryptedData[0] != 0 {
return nil, fmt.Errorf("invalid first-byte header signature (got=%o , expected=%o)", encryptedData[0], 0)
}
chunkSize := 1 << encryptedData[1]
encryptedData = encryptedData[2:]
var tasks []chan []byte
chunkIndex := 0
for i := 0; i < len(encryptedData); i += chunkSize {
if i+chunkSize > len(encryptedData) {
chunkSize = len(encryptedData) - i
}
chunk := make([]byte, chunkSize)
copy(chunk, encryptedData[i:i+chunkSize])
iv := chunk[:12]
aad := ic.calculateAAD(chunkIndex, i+chunkSize, len(encryptedData))
tasks = append(tasks, make(chan []byte))
go func(iv, chunk, aad []byte, task chan []byte) {
decrypted, err := ic.Decrypt(iv, chunk, aad)
if err != nil {
fmt.Println(err)
task <- nil
} else {
task <- decrypted
}
}(iv, chunk, aad, tasks[chunkIndex])
chunkIndex++
}
var result [][]byte
for _, task := range tasks {
decrypted := <-task
if decrypted == nil {
continue
}
result = append(result, decrypted)
}
var concatted []byte
for _, r := range result {
concatted = append(concatted, r...)
}
return concatted, nil
}
func (ic *ImageCryptor) calculateAAD(index, end, total int) []byte {
aad := make([]byte, 5)
i := 4
for index > 0 {
aad[i] = byte(index % 256)
index = index / 256
i--
}
if end >= total {
aad[0] = 1
}
return aad
}

43
libgm/debug/logger.go Normal file
View file

@ -0,0 +1,43 @@
package debug
import (
"fmt"
"time"
"github.com/mattn/go-colorable"
zerolog "github.com/rs/zerolog"
)
var colors = map[string]string{
"text": "\x1b[38;5;6m%s\x1b[0m",
"debug": "\x1b[32mDEBUG\x1b[0m",
"gray": "\x1b[38;5;8m%s\x1b[0m",
"info": "\x1b[38;5;111mINFO\x1b[0m",
"error": "\x1b[38;5;204mERROR\x1b[0m",
"fatal": "\x1b[38;5;52mFATAL\x1b[0m",
}
var output = zerolog.ConsoleWriter{
Out: colorable.NewColorableStdout(),
TimeFormat: time.ANSIC,
FormatLevel: func(i interface{}) string {
name := fmt.Sprintf("%s", i)
coloredName := colors[name]
return coloredName
},
FormatMessage: func(i interface{}) string {
coloredMsg := fmt.Sprintf(colors["text"], i)
return coloredMsg
},
FormatFieldName: func(i interface{}) string {
name := fmt.Sprintf("%s", i)
return fmt.Sprintf(colors["gray"], name+"=")
},
FormatFieldValue: func(i interface{}) string {
return fmt.Sprintf("%s", i)
},
NoColor: false,
}
func NewLogger() zerolog.Logger {
return zerolog.New(output).With().Timestamp().Logger()
}

26
libgm/event_handler.go Normal file
View file

@ -0,0 +1,26 @@
package textgapi
import (
"log"
"go.mau.fi/mautrix-gmessages/libgm/binary"
)
func (c *Client) handleEventOpCode(response *Response) {
//c.Logger.Debug().Any("res", response).Msg("got event response")
eventData := &binary.Event{}
decryptedErr := c.cryptor.DecryptAndDecodeData(response.Data.EncryptedData, eventData)
if decryptedErr != nil {
log.Fatal(decryptedErr)
}
switch evt := eventData.Event.(type) {
case *binary.Event_MessageEvent:
c.handleMessageEvent(response, evt)
case *binary.Event_ConversationEvent:
c.handleConversationEvent(response, evt)
case *binary.Event_UserAlertEvent:
c.handleUserAlertEvent(response, evt)
default:
c.Logger.Debug().Any("res", response).Msg("unknown event")
}
}

View file

@ -0,0 +1,67 @@
package events
import "go.mau.fi/mautrix-gmessages/libgm/cache"
type ConversationEvent interface {
GetConversation() *cache.Conversation
}
// Triggered when tabbing out of a conversation
type CONVERSATION_EXIT struct {
Conversation *cache.Conversation
}
func (c *CONVERSATION_EXIT) GetConversation() *cache.Conversation {
return c.Conversation
}
// Triggered when a conversation is archived
type CONVERSATION_ARCHIVED struct {
Conversation *cache.Conversation
}
func (c *CONVERSATION_ARCHIVED) GetConversation() *cache.Conversation {
return c.Conversation
}
// Triggered when a conversation is unarchived
type CONVERSATION_UNARCHIVED struct {
Conversation *cache.Conversation
}
func (c *CONVERSATION_UNARCHIVED) GetConversation() *cache.Conversation {
return c.Conversation
}
// Triggered when a conversation is deleted
type CONVERSATION_DELETED struct {
Conversation *cache.Conversation
}
func (c *CONVERSATION_DELETED) GetConversation() *cache.Conversation {
return c.Conversation
}
func NewConversationExit(conversation *cache.Conversation) ConversationEvent {
return &CONVERSATION_EXIT{
Conversation: conversation,
}
}
func NewConversationArchived(conversation *cache.Conversation) ConversationEvent {
return &CONVERSATION_ARCHIVED{
Conversation: conversation,
}
}
func NewConversationUnarchived(conversation *cache.Conversation) ConversationEvent {
return &CONVERSATION_UNARCHIVED{
Conversation: conversation,
}
}
func NewConversationDeleted(conversation *cache.Conversation) ConversationEvent {
return &CONVERSATION_DELETED{
Conversation: conversation,
}
}

65
libgm/events/messages.go Normal file
View file

@ -0,0 +1,65 @@
package events
import (
"go.mau.fi/mautrix-gmessages/libgm/cache"
)
type MessageEvent interface {
GetMessage() cache.Message
}
type MESSAGE_SENDING struct {
Message cache.Message
}
func (m *MESSAGE_SENDING) GetMessage() cache.Message {
return m.Message
}
func NewMessageSending(message cache.Message) MessageEvent {
return &MESSAGE_SENDING{
Message: message,
}
}
type MESSAGE_SENT struct {
Message cache.Message
}
func (m *MESSAGE_SENT) GetMessage() cache.Message {
return m.Message
}
func NewMessageSent(message cache.Message) MessageEvent {
return &MESSAGE_SENT{
Message: message,
}
}
type MESSAGE_RECEIVING struct {
Message cache.Message
}
func (m *MESSAGE_RECEIVING) GetMessage() cache.Message {
return m.Message
}
func NewMessageReceiving(message cache.Message) MessageEvent {
return &MESSAGE_RECEIVING{
Message: message,
}
}
type MESSAGE_RECEIVED struct {
Message cache.Message
}
func (m *MESSAGE_RECEIVED) GetMessage() cache.Message {
return m.Message
}
func NewMessageReceived(message cache.Message) MessageEvent {
return &MESSAGE_RECEIVED{
Message: message,
}
}

22
libgm/events/qr.go Normal file
View file

@ -0,0 +1,22 @@
package events
type QRCODE_UPDATED struct {
Image []byte
Height int
Width int
googleUrl string
}
func NewQrCodeUpdated(image []byte, height int, width int, googleUrl string) *QRCODE_UPDATED {
return &QRCODE_UPDATED{
Image: image,
Height: height,
Width: width,
googleUrl: googleUrl,
}
}
func (q *QRCODE_UPDATED) GetGoogleUrl() string {
return q.googleUrl
}

18
libgm/events/ready.go Normal file
View file

@ -0,0 +1,18 @@
package events
import (
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/util"
)
type CLIENT_READY struct {
Session *util.SessionResponse
Conversations []*binary.Conversation
}
func NewClientReady(session *util.SessionResponse, conversationList *binary.Conversations) *CLIENT_READY {
return &CLIENT_READY{
Session: session,
Conversations: conversationList.Conversations,
}
}

View file

@ -0,0 +1,24 @@
package events
type BROWSER_ACTIVE struct {
SessionId string
}
func NewBrowserActive(sessionId string) *BROWSER_ACTIVE {
return &BROWSER_ACTIVE{
SessionId: sessionId,
}
}
type BATTERY struct {}
func NewBattery() *BATTERY {
return &BATTERY{}
}
type DATA_CONNECTION struct {}
func NewDataConnection() *DATA_CONNECTION {
return &DATA_CONNECTION{}
}

View file

@ -0,0 +1,44 @@
package textgapi
import (
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/cache"
"go.mau.fi/mautrix-gmessages/libgm/events"
)
func (c *Client) handleConversationEvent(response *Response, evtData *binary.Event_ConversationEvent) {
lastCacheConv, notExists := c.cache.Conversations.GetConversation(evtData.ConversationEvent.Data.ConversationId)
evtConv := evtData.ConversationEvent.Data
//c.Logger.Debug().Any("convData", evtConv).Msg("Got conversation event!")
var eventData events.ConversationEvent
if evtConv.Status == 3 {
lastCacheConv.Delete()
eventData = events.NewConversationDeleted(lastCacheConv)
c.triggerEvent(eventData)
return
}
updatedCacheConv := c.cache.Conversations.UpdateConversation(evtConv)
eventData = c.getConversationEventInterface(lastCacheConv, updatedCacheConv, notExists)
if eventData == nil {
return
}
c.triggerEvent(eventData)
}
func (c *Client) getConversationEventInterface(lastCacheConv *cache.Conversation, updatedCacheConv *cache.Conversation, notExists error) events.ConversationEvent {
var evt events.ConversationEvent
convStatus := updatedCacheConv.Status
switch convStatus {
case 1: // unarchived
if lastCacheConv.Status != 1 {
evt = events.NewConversationUnarchived(updatedCacheConv)
}
case 2: // archived
evt = events.NewConversationArchived(updatedCacheConv)
case 3: // deleted
evt = events.NewConversationDeleted(updatedCacheConv)
}
return evt
}

57
libgm/handler_message.go Normal file
View file

@ -0,0 +1,57 @@
package textgapi
import (
"log"
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/cache"
//"github.com/0xzer/textgapi/cache"
"go.mau.fi/mautrix-gmessages/libgm/events"
)
func (c *Client) handleMessageEvent(response *Response, evtData *binary.Event_MessageEvent) {
msgData := evtData.MessageEvent.Data
currConv, convNotFound := c.cache.Conversations.GetConversation(msgData.ConversationId)
if convNotFound != nil {
log.Fatal(convNotFound)
}
lastCacheMsg, errGetMsg := currConv.GetMessage(msgData.MessageId)
updatedCacheMsg := currConv.UpdateMessage(msgData)
eventData := c.getMessageEventInterface(currConv, lastCacheMsg, errGetMsg, updatedCacheMsg)
if eventData == nil {
return
}
c.triggerEvent(eventData)
}
func (c *Client) getMessageEventInterface(currConv *cache.Conversation, lastCacheMsg cache.Message, lastCacheErr error, evtMsg cache.Message) events.MessageEvent {
var evt events.MessageEvent
msgStatusCode := evtMsg.MessageStatus.Code
fromMe := evtMsg.FromMe()
switch msgStatusCode {
case 5: // sending
if lastCacheErr != nil {
if fromMe {
evt = events.NewMessageSending(evtMsg)
} else {
evt = events.NewMessageReceiving(evtMsg)
}
}
case 1: // sent
if lastCacheMsg.MessageStatus.Code != 1 {
if fromMe {
evt = events.NewMessageSent(evtMsg)
} else {
evt = events.NewMessageReceived(evtMsg)
}
}
default:
c.Logger.Debug().Any("data", evtMsg).Msg("Unknown msgstatus code")
}
return evt
}

View file

@ -0,0 +1,23 @@
package textgapi
import (
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/events"
)
func (c *Client) handleUserAlertEvent(response *Response, evtData *binary.Event_UserAlertEvent) {
switch evtData.UserAlertEvent.AlertType {
case 2:
browserActive := events.NewBrowserActive(response.Data.RequestId)
c.triggerEvent(browserActive)
return
case 5, 6:
batteryEvt := events.NewBattery()
c.triggerEvent(batteryEvt)
return
case 3, 4:
dataConnectionEvt := events.NewDataConnection()
c.triggerEvent(dataConnectionEvt)
return
}
}

171
libgm/image_builder.go Normal file
View file

@ -0,0 +1,171 @@
package textgapi
import (
"fmt"
"os"
validator "github.com/gabriel-vasile/mimetype"
"go.mau.fi/mautrix-gmessages/libgm/crypto"
"go.mau.fi/mautrix-gmessages/libgm/util"
)
type ImageType struct {
Extension string
Format string
Type int64
}
var ImageTypes = map[string]ImageType{
"image/jpeg": {Extension: "jpeg", Format: "image/jpeg", Type: 1},
"image/jpg": {Extension: "jpg", Format: "image/jpg", Type: 2},
"image/png": {Extension: "png", Format: "image/png", Type: 3},
"image/gif": {Extension: "gif", Format: "image/gif", Type: 4},
"image/wbmp": {Extension: "wbmp", Format: "image/wbmp", Type: 5},
"image/bmp": {Extension: "bmp", Format: "image/bmp", Type: 6},
"image/x-ms-bmp": {Extension: "bmp", Format: "image/x-ms-bmp", Type: 6},
"audio/aac": {Extension: "aac", Format: "audio/aac", Type: 14},
"audio/amr": {Extension: "amr", Format: "audio/amr", Type: 15},
"audio/mp3": {Extension: "mp3", Format: "audio/mp3", Type: 16},
"audio/mpeg": {Extension: "mpeg", Format: "audio/mpeg", Type: 17},
"audio/mpg": {Extension: "mpg", Format: "audio/mpg", Type: 18},
"audio/mp4": {Extension: "mp4", Format: "audio/mp4", Type: 19},
"audio/mp4-latm": {Extension: "latm", Format: "audio/mp4-latm", Type: 20},
"audio/3gpp": {Extension: "3gpp", Format: "audio/3gpp", Type: 21},
"audio/ogg": {Extension: "ogg", Format: "audio/ogg", Type: 22},
"video/mp4": {Extension: "mp4", Format: "video/mp4", Type: 8},
"video/3gpp2": {Extension: "3gpp2", Format: "video/3gpp2", Type: 9},
"video/3gpp": {Extension: "3gpp", Format: "video/3gpp", Type: 10},
"video/webm": {Extension: "webm", Format: "video/webm", Type: 11},
"video/x-matroska": {Extension: "mkv", Format: "video/x-matroska", Type: 12},
"application/pdf": {Extension: "pdf", Format: "application/pdf", Type: 25},
"application/txt": {Extension: "txt", Format: "application/txt", Type: 26},
"application/html": {Extension: "html", Format: "application/html", Type: 27},
"application/msword": {Extension: "doc", Format: "application/msword", Type: 28},
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": {Extension: "docx", Format: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", Type: 29},
"application/vnd.openxmlformats-officedocument.presentationml.presentation": {Extension: "pptx", Format: "application/vnd.openxmlformats-officedocument.presentationml.presentation", Type: 30},
"application/vnd.ms-powerpoint": {Extension: "ppt", Format: "application/vnd.ms-powerpoint", Type: 31},
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": {Extension: "xlsx", Format: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", Type: 32},
"application/vnd.ms-excel": {Extension: "xls", Format: "application/vnd.ms-excel", Type: 33},
"application/vnd.android.package-archive": {Extension: "apk", Format: "application/vnd.android.package-archive", Type: 34},
"application/zip": {Extension: "zip", Format: "application/zip", Type: 35},
"application/java-archive": {Extension: "jar", Format: "application/java-archive", Type: 36},
"text/x-vCalendar": {Extension: "vcs", Format: "text/x-vCalendar", Type: 38},
"text/x-vcalendar": {Extension: "ics", Format: "text/x-vcalendar", Type: 39},
"text/calendar": {Extension: "ics", Format: "text/calendar", Type: 40},
"application/vcs": {Extension: "vcs", Format: "application/vcs", Type: 41},
"application/ics": {Extension: "ics", Format: "application/ics", Type: 42},
"application/hbs-vcs": {Extension: "vcs", Format: "application/hbs-vcs", Type: 43},
"text/vcard": {Extension: "vcard", Format: "text/vcard", Type: 24},
"text/x-vcard": {Extension: "vcard", Format: "text/x-vcard", Type: 24},
}
type Image struct {
imageCryptor *crypto.ImageCryptor
imageName string
imageId string
imageType ImageType
imageBytes []byte
imageSize int64
}
func (i *Image) GetEncryptedBytes() ([]byte, error) {
encryptedBytes, encryptErr := i.imageCryptor.EncryptData(i.imageBytes)
if encryptErr != nil {
return nil, encryptErr
}
return encryptedBytes, nil
}
func (i *Image) GetImageCryptor() *crypto.ImageCryptor {
return i.imageCryptor
}
func (i *Image) GetImageName() string {
return i.imageName
}
func (i *Image) GetImageBytes() []byte {
return i.imageBytes
}
func (i *Image) GetImageSize() int64 {
return i.imageSize
}
func (i *Image) GetImageType() ImageType {
return i.imageType
}
func (i *Image) GetImageId() string {
return i.imageId
}
func (mb *MessageBuilder) AddImageFromPath(filePath string) *MessageBuilder {
if mb.err != nil {
return mb
}
file, err := os.ReadFile(filePath)
if err != nil {
mb.err = err
return mb
}
return mb.AddImage(file)
}
// This is the equivalent of dragging an image into the window on messages web
//
// Keep in mind that adding an image to a MessageBuilder will also upload the image to googles server
func (mb *MessageBuilder) AddImage(imgBytes []byte) *MessageBuilder {
if mb.err != nil {
return mb
}
newImage, newImageErr := mb.newImageData(imgBytes)
if newImageErr != nil {
mb.err = newImageErr
return mb
}
startUploadImage, failedUpload := mb.client.StartUploadMedia(newImage)
if failedUpload != nil {
mb.err = failedUpload
return mb
}
finalizedImage, failedFinalize := mb.client.FinalizeUploadMedia(startUploadImage)
if failedFinalize != nil {
mb.err = failedFinalize
return mb
}
mb.images = append(mb.images, finalizedImage)
return mb
}
func (mb *MessageBuilder) newImageData(imgBytes []byte) (*Image, error) {
imgFormat := validator.Detect(imgBytes)
if imgFormat.String() == "text/plain" {
return nil, fmt.Errorf("could not validate media content-type: received %s", imgFormat.String())
}
imgType := ImageTypes[imgFormat.String()]
imageId := util.GenerateImageId()
imageName := util.RandStr(8) + "." + imgType.Extension
decryptionKey, err := crypto.GenerateKey(32)
if err != nil {
return nil, err
}
imageCryptor, cryptorErr := crypto.NewImageCryptor(decryptionKey)
if cryptorErr != nil {
return nil, cryptorErr
}
return &Image{
imageCryptor: imageCryptor,
imageId: imageId,
imageBytes: imgBytes,
imageType: imgType,
imageSize: int64(len(imgBytes)),
imageName: imageName,
}, nil
}

78
libgm/instructions.go Normal file
View file

@ -0,0 +1,78 @@
package textgapi
import (
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/crypto"
)
const (
ROUTING_OPCODE = 19
MSG_TYPE_TWO = 2
MSG_TYPE_SIXTEEN = 16
/*
Session
*/
PREPARE_NEW_SESSION_OPCODE = 31
NEW_SESSION_OPCODE = 16
/*
Conversation
*/
LIST_CONVERSATIONS = 1
SET_ACTIVE_CONVERSATION = 22
OPEN_CONVERSATION = 21
FETCH_MESSAGES_CONVERSATION = 2
SEND_TEXT_MESSAGE = 3
)
type Instruction struct {
cryptor *crypto.Cryptor
RoutingOpCode int64
Opcode int64
MsgType int64
EncryptedData []byte
DecryptedProtoMessage proto.Message
ExpectedResponses int64 // count expected responses
ProcessResponses func(responses []*Response) (interface{}, error) // function that decodes & decrypts the slice into appropriate response
}
func (c *Client) EncryptPayloadData(message protoreflect.Message) ([]byte, error) {
protoBytes, err1 := binary.EncodeProtoMessage(message.Interface())
if err1 != nil {
return nil, err1
}
encryptedBytes, err := c.cryptor.Encrypt(protoBytes)
if err != nil {
return nil, err
}
return encryptedBytes, nil
}
type Instructions struct {
data map[int64]*Instruction
}
func NewInstructions(cryptor *crypto.Cryptor) *Instructions {
return &Instructions{
data: map[int64]*Instruction{
PREPARE_NEW_SESSION_OPCODE: {cryptor, ROUTING_OPCODE, PREPARE_NEW_SESSION_OPCODE, MSG_TYPE_TWO, nil, &binary.PrepareNewSession{}, 1, nil},
NEW_SESSION_OPCODE: {cryptor, ROUTING_OPCODE, NEW_SESSION_OPCODE, MSG_TYPE_TWO, nil, &binary.NewSession{}, 2, nil}, // create new session
LIST_CONVERSATIONS: {cryptor, ROUTING_OPCODE, LIST_CONVERSATIONS, MSG_TYPE_SIXTEEN, nil, &binary.Conversations{}, 1, nil}, // list conversations
//22: {cryptor,19,22,2,nil,nil}, // SET ACTIVE SESSION WINDOW
OPEN_CONVERSATION: {cryptor, ROUTING_OPCODE, OPEN_CONVERSATION, MSG_TYPE_TWO, nil, nil, 2, nil}, // open conversation
FETCH_MESSAGES_CONVERSATION: {cryptor, ROUTING_OPCODE, FETCH_MESSAGES_CONVERSATION, MSG_TYPE_TWO, nil, &binary.FetchMessagesResponse{}, 1, nil}, // fetch messages in convo
SEND_TEXT_MESSAGE: {cryptor, ROUTING_OPCODE, SEND_TEXT_MESSAGE, MSG_TYPE_TWO, nil, &binary.SendMessageResponse{}, 1, nil},
//3: {cryptor,19,3,2,nil,&binary.SendMessageResponse{}}, // send text message
},
}
}
func (i *Instructions) GetInstruction(key int64) (*Instruction, bool) {
instruction, ok := i.data[key]
return instruction, ok
}

View file

@ -0,0 +1,53 @@
package json_proto
import (
"fmt"
"google.golang.org/protobuf/reflect/protoreflect"
)
func Deserialize(data []interface{}, m protoreflect.Message) error {
for i := 0; i < m.Descriptor().Fields().Len(); i++ {
fieldDescriptor := m.Descriptor().Fields().Get(i)
index := int(fieldDescriptor.Number()) - 1
if index < 0 || index >= len(data) || data[index] == nil {
continue
}
val := data[index]
switch fieldDescriptor.Kind() {
case protoreflect.MessageKind:
nestedData, ok := val.([]interface{})
if !ok {
return fmt.Errorf("expected slice, got %T", val)
}
nestedMessage := m.NewField(fieldDescriptor).Message()
if err := Deserialize(nestedData, nestedMessage); err != nil {
return err
}
m.Set(fieldDescriptor, protoreflect.ValueOfMessage(nestedMessage))
case protoreflect.BytesKind:
bytes, ok := val.([]byte)
if !ok {
return fmt.Errorf("expected bytes, got %T", val)
}
m.Set(fieldDescriptor, protoreflect.ValueOfBytes(bytes))
case protoreflect.Int32Kind, protoreflect.Int64Kind:
num, ok := val.(float64)
if !ok {
return fmt.Errorf("expected number, got %T", val)
}
m.Set(fieldDescriptor, protoreflect.ValueOf(int64(num)))
case protoreflect.StringKind:
str, ok := val.(string)
if !ok {
return fmt.Errorf("expected string, got %T", val)
}
m.Set(fieldDescriptor, protoreflect.ValueOf(str))
default:
// ignore fields of other types
}
}
return nil
}

View file

@ -0,0 +1,100 @@
package json_proto
/*
in protobuf, a message looks like this:
message SomeMessage {
string stringField1 = 1;
int64 intField = 6;
bytes byteField = 9;
}
but when this function is done serializing this protobuf message into a slice, it should look something like this:
[
"someString",
nil,
nil,
nil,
nil,
6,
nil,
nil,
"\x9\x91\x942"
]
Any integer should be translated into int64, it doesn't matter if it's defined as int32 in the proto schema.
In the finished serialized slice it should be int64.
Let's also take in count where there is a message nested inside a message:
message SomeMessage {
string stringField1 = 1;
NestedMessage1 nestedMessage1 = 2;
int64 intField = 6;
bytes byteField = 9;
}
message NestedMessage1 {
string msg1 = 1;
}
Then the serialized output would be:
[
"someString",
["msg1FieldValue"],
nil,
nil,
nil,
6,
nil,
nil,
"\x9\x91\x942"
]
This means that any slice inside of the current slice, indicates another message nested inside of it.
*/
import (
"google.golang.org/protobuf/reflect/protoreflect"
)
func Serialize(m protoreflect.Message) ([]interface{}, error) {
maxFieldNumber := 0
for i := 0; i < m.Descriptor().Fields().Len(); i++ {
fieldNumber := int(m.Descriptor().Fields().Get(i).Number())
if fieldNumber > maxFieldNumber {
maxFieldNumber = fieldNumber
}
}
serialized := make([]interface{}, maxFieldNumber)
for i := 0; i < m.Descriptor().Fields().Len(); i++ {
fieldDescriptor := m.Descriptor().Fields().Get(i)
fieldValue := m.Get(fieldDescriptor)
fieldNumber := int(fieldDescriptor.Number())
switch fieldDescriptor.Kind() {
case protoreflect.MessageKind:
if m.Has(fieldDescriptor) {
serializedMsg, err := Serialize(fieldValue.Message().Interface().ProtoReflect())
if err != nil {
return nil, err
}
serialized[fieldNumber-1] = serializedMsg
}
case protoreflect.BytesKind:
if m.Has(fieldDescriptor) {
serialized[fieldNumber-1] = fieldValue.Bytes()
}
case protoreflect.Int32Kind, protoreflect.Int64Kind:
if m.Has(fieldDescriptor) {
serialized[fieldNumber-1] = fieldValue.Int()
}
case protoreflect.StringKind:
if m.Has(fieldDescriptor) {
serialized[fieldNumber-1] = fieldValue.String()
}
default:
// ignore fields of other types
}
}
return serialized, nil
}

166
libgm/media_processor.go Normal file
View file

@ -0,0 +1,166 @@
package textgapi
import (
"bytes"
"errors"
"io"
"log"
"net/http"
"strconv"
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/crypto"
"go.mau.fi/mautrix-gmessages/libgm/util"
)
type StartGoogleUpload struct {
UploadId string
UploadUrl string
UploadStatus string
ChunkGranularity int64
ControlUrl string
Image *Image
EncryptedMediaBytes []byte
}
type MediaUpload struct {
MediaId string
MediaNumber int64
Image *Image
}
var (
errStartUploadMedia = errors.New("failed to start uploading media")
errFinalizeUploadMedia = errors.New("failed to finalize uploading media")
)
func (c *Client) FinalizeUploadMedia(upload *StartGoogleUpload) (*MediaUpload, error) {
imageType := upload.Image.GetImageType()
encryptedImageSize := strconv.Itoa(len(upload.EncryptedMediaBytes))
log.Println("EncryptedImageSize:", encryptedImageSize)
finalizeUploadHeaders := util.NewMediaUploadHeaders(encryptedImageSize, "upload, finalize", "0", imageType.Format, "")
req, reqErr := http.NewRequest("POST", upload.UploadUrl, bytes.NewBuffer(upload.EncryptedMediaBytes))
if reqErr != nil {
return nil, reqErr
}
req.Header = *finalizeUploadHeaders
res, resErr := c.http.Do(req)
if resErr != nil {
log.Fatal(resErr)
}
statusCode := res.StatusCode
if statusCode != 200 {
return nil, errFinalizeUploadMedia
}
defer res.Body.Close()
rHeaders := res.Header
googleResponse, err3 := io.ReadAll(res.Body)
if err3 != nil {
return nil, err3
}
uploadStatus := rHeaders.Get("x-goog-upload-status")
log.Println("Upload Status: ", uploadStatus)
mediaIds := &binary.UploadMediaResponse{}
err3 = crypto.DecodeAndEncodeB64(string(googleResponse), mediaIds)
if err3 != nil {
return nil, err3
}
return &MediaUpload{
MediaId: mediaIds.Media.MediaId,
MediaNumber: mediaIds.Media.MediaNumber,
Image: upload.Image,
}, nil
}
func (c *Client) StartUploadMedia(image *Image) (*StartGoogleUpload, error) {
imageType := image.GetImageType()
encryptedImageBytes, encryptErr := image.GetEncryptedBytes()
if encryptErr != nil {
return nil, encryptErr
}
encryptedImageSize := strconv.Itoa(len(encryptedImageBytes))
startUploadHeaders := util.NewMediaUploadHeaders(encryptedImageSize, "start", "", imageType.Format, "resumable")
startUploadPayload, buildPayloadErr := c.buildStartUploadPayload()
if buildPayloadErr != nil {
return nil, buildPayloadErr
}
req, reqErr := http.NewRequest("POST", util.UPLOAD_MEDIA, bytes.NewBuffer([]byte(startUploadPayload)))
if reqErr != nil {
return nil, reqErr
}
req.Header = *startUploadHeaders
res, resErr := c.http.Do(req)
if resErr != nil {
log.Fatal(resErr)
}
statusCode := res.StatusCode
if statusCode != 200 {
return nil, errStartUploadMedia
}
rHeaders := res.Header
chunkGranularity, convertErr := strconv.Atoi(rHeaders.Get("x-goog-upload-chunk-granularity"))
if convertErr != nil {
return nil, convertErr
}
uploadResponse := &StartGoogleUpload{
UploadId: rHeaders.Get("x-guploader-uploadid"),
UploadUrl: rHeaders.Get("x-goog-upload-url"),
UploadStatus: rHeaders.Get("x-goog-upload-status"),
ChunkGranularity: int64(chunkGranularity),
ControlUrl: rHeaders.Get("x-goog-upload-control-url"),
Image: image,
EncryptedMediaBytes: encryptedImageBytes,
}
return uploadResponse, nil
}
func (c *Client) buildStartUploadPayload() (string, error) {
decodedRpcKey, err := crypto.Base64DecodeStandard(c.rpcKey)
if err != nil {
return "", err
}
requestId := util.RandomUUIDv4()
protoData := &binary.StartMediaUploadPayload{
ImageType: 1,
AuthData: &binary.AuthMessageBytes{
RequestId: requestId,
RpcKey: decodedRpcKey,
Date: &binary.Date{
Year: 2023,
Seq1: 6,
Seq2: 8,
Seq3: 4,
Seq4: 6,
},
},
Mobile: c.devicePair.Mobile,
}
protoDataEncoded, protoEncodeErr := crypto.EncodeProtoB64(protoData)
if protoEncodeErr != nil {
return "", protoEncodeErr
}
return protoDataEncoded, nil
}

174
libgm/message_builder.go Normal file
View file

@ -0,0 +1,174 @@
package textgapi
import (
"errors"
"log"
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/util"
)
var (
errContentNotSet = errors.New("failed to build MessageBuilder: content must be larger than length 0")
errConversationIdNotSet = errors.New("failed to build MessageBuilder: conversationId is empty")
errSelfParticipantIdNotSet = errors.New("failed to build MessageBuilder: selfParticipantId is empty")
)
type MessageBuilder struct {
client *Client
content string
conversationId string
tmpId string
selfParticipantId string
images []*MediaUpload
err error
}
// Add this method to retrieve the stored error
func (mb *MessageBuilder) Err() error {
return mb.err
}
func (mb *MessageBuilder) GetImages() []*MediaUpload {
return mb.images
}
func (mb *MessageBuilder) GetContent() string {
return mb.content
}
func (mb *MessageBuilder) SetContent(content string) *MessageBuilder {
mb.content = content
return mb
}
func (mb *MessageBuilder) GetConversationId() string {
return mb.conversationId
}
func (mb *MessageBuilder) SetConversationId(conversationId string) *MessageBuilder {
mb.conversationId = conversationId
return mb
}
func (mb *MessageBuilder) GetSelfParticipantId() string {
return mb.selfParticipantId
}
// sendmessage function will set this automatically but if u want to set it yourself feel free
func (mb *MessageBuilder) SetSelfParticipantId(participantId string) *MessageBuilder {
mb.selfParticipantId = participantId
return mb
}
func (mb *MessageBuilder) GetTmpId() string {
return mb.tmpId
}
// sendmessage function will set this automatically but if u want to set it yourself feel free
func (mb *MessageBuilder) SetTmpId(tmpId string) *MessageBuilder {
mb.tmpId = tmpId
return mb
}
func (mb *MessageBuilder) Build() (*binary.SendMessagePayload, error) {
if mb.conversationId == "" {
return nil, errConversationIdNotSet
}
if mb.selfParticipantId == "" {
return nil, errSelfParticipantIdNotSet
}
if mb.content == "" {
return nil, errContentNotSet
}
if mb.tmpId == "" {
mb.tmpId = util.GenerateTmpId()
}
return mb.newSendConversationMessage(), nil
}
func (c *Client) NewMessageBuilder() *MessageBuilder {
mb := &MessageBuilder{
client: c,
}
tmpId := util.GenerateTmpId()
mb.SetTmpId(tmpId)
return mb
}
func (mb *MessageBuilder) newSendConversationMessage() *binary.SendMessagePayload {
convId := mb.GetConversationId()
content := mb.GetContent()
selfParticipantId := mb.GetSelfParticipantId()
tmpId := mb.GetTmpId()
messageInfo := make([]*binary.MessageInfo, 0)
messageInfo = append(messageInfo, &binary.MessageInfo{Data: &binary.MessageInfo_MessageContent{
MessageContent: &binary.MessageContent{
Content: content,
},
}})
mb.appendImagesPayload(&messageInfo)
sendMsgPayload := &binary.SendMessagePayload{
ConversationId: convId,
MessagePayload: &binary.MessagePayload{
TmpId: tmpId,
ConversationId: convId,
SelfParticipantId: selfParticipantId,
MessageInfo: messageInfo,
TmpId2: tmpId,
},
TmpId: tmpId,
}
if len(content) > 0 {
sendMsgPayload.MessagePayload.MessagePayloadContent = &binary.MessagePayloadContent{
MessageContent: &binary.MessageContent{
Content: content,
},
}
}
mb.client.Logger.Debug().Any("sendMsgPayload", sendMsgPayload).Msg("sendMessagePayload")
return sendMsgPayload
}
func (mb *MessageBuilder) appendImagesPayload(messageInfo *[]*binary.MessageInfo) {
if len(mb.images) <= 0 {
log.Println("0 images to append, ignoring")
return
}
for _, media := range mb.images {
imgData := mb.newImageContent(media)
*messageInfo = append(*messageInfo, imgData)
}
}
func (mb *MessageBuilder) newImageContent(media *MediaUpload) *binary.MessageInfo {
imageMessage := &binary.MessageInfo{
Data: &binary.MessageInfo_ImageContent{
ImageContent: &binary.ImageContent{
SomeNumber: media.Image.GetImageType().Type,
ImageId: media.MediaId,
ImageName: media.Image.GetImageName(),
Size: media.Image.GetImageSize(),
DecryptionKey: media.Image.GetImageCryptor().GetKey(),
},
},
}
mb.client.Logger.Debug().Any("imageMessage", imageMessage).Msg("New Image Content")
return imageMessage
}

25
libgm/misc.go Normal file
View file

@ -0,0 +1,25 @@
package textgapi
import (
"log"
"os"
"go.mau.fi/mautrix-gmessages/libgm/builders"
"go.mau.fi/mautrix-gmessages/libgm/util"
)
type Misc struct {
client *Client
}
func (m *Misc) TenorSearch(searchOpts *builders.TenorSearch) (interface{}, error) {
searchQuery, buildErr := searchOpts.Build()
if buildErr != nil {
return nil, buildErr
}
uri := util.TENOR_SEARCH_GIF + searchQuery
log.Println(uri)
os.Exit(1)
return nil, nil
}

71
libgm/msg_handler.go Normal file
View file

@ -0,0 +1,71 @@
package textgapi
import (
"encoding/json"
"fmt"
"log"
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/json_proto"
)
func (r *RPC) HandleRPCMsg(msgArr []interface{}) {
/*
if data[0] == 44 { // ','
data = data[1:]
}
var msgArr []interface{}
err := r.tryUnmarshalJSON(data, &msgArr)
if err != nil {
r.client.Logger.Error().Err(fmt.Errorf("got invalid json string %s", string(data))).Msg("rpc msg err")
r.HandleByLength(data)
return
}
*/
response := &binary.RPCResponse{}
deserializeErr := json_proto.Deserialize(msgArr, response.ProtoReflect())
if deserializeErr != nil {
r.client.Logger.Error().Err(fmt.Errorf("failed to deserialize response %s", msgArr)).Msg("rpc deserialize msg err")
return
}
//r.client.Logger.Debug().Any("byteLength", len(data)).Any("unmarshaled", response).Any("raw", string(data)).Msg("RPC Msg")
if response.Data == nil {
r.client.Logger.Error().Err(fmt.Errorf("Response data was nil %s", msgArr)).Msg("rpc msg data err")
return
}
if response.Data.RoutingOpCode == 19 {
parsedResponse, failedParse := r.client.sessionHandler.NewResponse(response)
if failedParse != nil {
log.Fatal(failedParse)
}
//hasBody := parsedResponse.Data.EncryptedData == nil
//r.client.Logger.Info().Any("msgData", parsedResponse).Msg("Got event!")
r.client.sessionHandler.addResponseAck(parsedResponse.ResponseId)
_, waitingForResponse := r.client.sessionHandler.requests[parsedResponse.Data.RequestId]
//log.Println(fmt.Sprintf("%v %v %v %v %v %v %v", parsedResponse.RoutingOpCode, parsedResponse.Data.Opcode, parsedResponse.Data.Sub, parsedResponse.Data.Third, parsedResponse.Data.Field9, hasBody, waitingForResponse))
//r.client.Logger.Debug().Any("waitingForResponse?", waitingForResponse).Msg("Got rpc response from server")
if parsedResponse.Data.Opcode == 16 || waitingForResponse {
if waitingForResponse {
r.client.sessionHandler.respondToRequestChannel(parsedResponse)
return
}
if parsedResponse.Data.Opcode == 16 {
r.client.handleEventOpCode(parsedResponse)
}
} else {
}
} else {
r.client.handleSeperateOpCode(response.Data)
}
}
func (r *RPC) tryUnmarshalJSON(jsonData []byte, msgArr *[]interface{}) error {
err := json.Unmarshal(jsonData, &msgArr)
return err
}
func (r *RPC) HandleByLength(data []byte) {
r.client.Logger.Debug().Any("byteLength", len(data)).Any("corrupt raw", string(data)).Msg("RPC Corrupt json")
}

39
libgm/opcode_handler.go Normal file
View file

@ -0,0 +1,39 @@
package textgapi
import (
"log"
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/crypto"
)
func (c *Client) handleSeperateOpCode(msgData *binary.MessageData) {
decodedBytes, err := crypto.Base64DecodeStandard(msgData.EncodedData)
if err != nil {
log.Fatal(err)
}
switch msgData.RoutingOpCode {
case 14: // paired successful
decodedData := &binary.Container{}
err = binary.DecodeProtoMessage(decodedBytes, decodedData)
if err != nil {
log.Fatal(err)
}
c.Logger.Debug().Any("data", decodedData).Msg("Paired device decoded data")
c.pairer.pairCallback(decodedData)
default:
decodedData := &binary.EncodedResponse{}
err = binary.DecodeProtoMessage(decodedBytes, decodedData)
if err != nil {
log.Fatal(err)
}
if (decodedData.Sub && decodedData.Third != 0) && decodedData.EncryptedData != nil {
bugleData := &binary.BugleBackendService{}
err = c.cryptor.DecryptAndDecodeData(decodedData.EncryptedData, bugleData)
if err != nil {
log.Fatal(err)
}
c.handleBugleOpCode(bugleData)
}
}
}

161
libgm/pair.go Normal file
View file

@ -0,0 +1,161 @@
package textgapi
import (
"io"
"log"
"time"
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/crypto"
"go.mau.fi/mautrix-gmessages/libgm/payload"
"go.mau.fi/mautrix-gmessages/libgm/util"
)
type Pairer struct {
client *Client
KeyData *crypto.JWK
ticker *time.Ticker
tickerTime time.Duration
qrCodePx int
pairingKey []byte
}
/*
refreshQrCodeTime is the interval to refresh the qr code in seconds, this is usually 20 seconds.
*/
func (c *Client) NewPairer(keyData *crypto.JWK, refreshQrCodeTime int) (*Pairer, error) {
if keyData == nil {
var err error
keyData, err = crypto.GenerateECDSA_P256_JWK()
if err != nil {
c.Logger.Error().Any("data", keyData).Msg(err.Error())
return nil, err
}
}
p := &Pairer{
client: c,
KeyData: keyData,
qrCodePx: 214,
tickerTime: time.Duration(refreshQrCodeTime) * time.Second,
}
c.pairer = p
return p, nil
}
func (p *Pairer) SetQRCodePx(pixels int) {
p.qrCodePx = pixels
}
func (p *Pairer) RegisterPhoneRelay() (*binary.RegisterPhoneRelayResponse, error) {
body, _, err := payload.RegisterPhoneRelay(p.KeyData)
if err != nil {
p.client.Logger.Err(err)
return &binary.RegisterPhoneRelayResponse{}, err
}
//p.client.Logger.Debug().Any("keyByteLength", len(jsonPayload.EcdsaKeysContainer.EcdsaKeys.EncryptedKeys)).Any("json", jsonPayload).Any("base64", body).Msg("RegisterPhoneRelay Payload")
relayResponse, reqErr := p.client.MakeRelayRequest(util.REGISTER_PHONE_RELAY, body)
if reqErr != nil {
p.client.Logger.Err(reqErr)
return nil, err
}
responseBody, err2 := io.ReadAll(relayResponse.Body)
if err2 != nil {
return nil, err2
}
relayResponse.Body.Close()
res := &binary.RegisterPhoneRelayResponse{}
err3 := binary.DecodeProtoMessage(responseBody, res)
if err3 != nil {
return nil, err3
}
p.pairingKey = res.GetPairingKey()
qrCode, qrErr := p.GenerateQRCode(p.qrCodePx)
if qrErr != nil {
return nil, qrErr
}
p.client.triggerEvent(qrCode)
p.startRefreshRelayTask()
return res, err
}
func (p *Pairer) startRefreshRelayTask() {
if p.ticker != nil {
p.ticker.Stop()
}
ticker := time.NewTicker(30 * time.Second)
p.ticker = ticker
go func() {
for range ticker.C {
p.RefreshPhoneRelay()
}
}()
}
func (p *Pairer) RefreshPhoneRelay() {
body, _, err := payload.RefreshPhoneRelay(p.client.rpcKey)
if err != nil {
p.client.Logger.Err(err).Msg("refresh phone relay err")
return
}
//p.client.Logger.Debug().Any("keyByteLength", len(jsonPayload.PhoneRelay.RpcKey)).Any("json", jsonPayload).Any("base64", body).Msg("RefreshPhoneRelay Payload")
relayResponse, reqErr := p.client.MakeRelayRequest(util.REFRESH_PHONE_RELAY, body)
if reqErr != nil {
p.client.Logger.Err(reqErr).Msg("refresh phone relay err")
}
responseBody, err2 := io.ReadAll(relayResponse.Body)
defer relayResponse.Body.Close()
if err2 != nil {
p.client.Logger.Err(err2).Msg("refresh phone relay err")
}
p.client.Logger.Debug().Any("responseLength", len(responseBody)).Msg("Response Body Length")
res := &binary.RefreshPhoneRelayResponse{}
err3 := binary.DecodeProtoMessage(responseBody, res)
if err3 != nil {
p.client.Logger.Err(err3)
}
p.pairingKey = res.GetPairKey()
p.client.Logger.Debug().Any("res", res).Msg("RefreshPhoneRelayResponse")
qrCode, qrErr := p.GenerateQRCode(p.qrCodePx)
if qrErr != nil {
log.Fatal(qrErr)
}
p.client.triggerEvent(qrCode)
}
func (p *Pairer) GetWebEncryptionKey() {
body, _, err2 := payload.GetWebEncryptionKey(p.client.rpc.webAuthKey)
if err2 != nil {
p.client.Logger.Err(err2).Msg("web encryption key err")
return
}
//p.client.Logger.Debug().Any("keyByteLength", len(rawData.PhoneRelay.RpcKey)).Any("json", rawData).Any("base64", body).Msg("GetWebEncryptionKey Payload")
webKeyResponse, reqErr := p.client.MakeRelayRequest(util.GET_WEB_ENCRYPTION_KEY, body)
if reqErr != nil {
p.client.Logger.Err(reqErr).Msg("Web encryption key request err")
}
responseBody, err2 := io.ReadAll(webKeyResponse.Body)
defer webKeyResponse.Body.Close()
if err2 != nil {
p.client.Logger.Err(err2).Msg("Web encryption key read response err")
return
}
//p.client.Logger.Debug().Any("responseLength", len(responseBody)).Any("raw", responseBody).Msg("Response Body Length")
parsedResponse := &binary.WebEncryptionKeyResponse{}
err2 = binary.DecodeProtoMessage(responseBody, parsedResponse)
if err2 != nil {
p.client.Logger.Err(err2).Msg("Parse webkeyresponse into proto struct error")
}
key := crypto.EncodeBase64Standard(p.client.rpc.webAuthKey)
p.ticker.Stop()
reconnectErr := p.client.Reconnect(key)
if reconnectErr != nil {
log.Fatal(reconnectErr)
}
}
func (p *Pairer) pairCallback(pairData *binary.Container) {
p.client.rpc.webAuthKey = pairData.PairDeviceData.WebAuthKeyData.WebAuthKey
p.client.ttl = pairData.PairDeviceData.WebAuthKeyData.ValidFor
p.client.devicePair = &DevicePair{Mobile: pairData.PairDeviceData.Mobile, Browser: pairData.PairDeviceData.Browser}
p.client.pairer.GetWebEncryptionKey()
}

View file

@ -0,0 +1 @@
package payload

View file

@ -0,0 +1,31 @@
package payload
import (
"log"
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/util"
)
func GetWebEncryptionKey(WebPairKey []byte) ([]byte, *binary.Container, error) {
log.Println(WebPairKey)
id := util.RandomUUIDv4()
payload := &binary.Container{
PhoneRelay: &binary.PhoneRelayBody{
Id: id,
RpcKey: WebPairKey,
Date: &binary.Date{
Year: 2023,
Seq1: 6,
Seq2: 8,
Seq3: 4,
Seq4: 6,
},
},
}
encodedPayload, err2 := binary.EncodeProtoMessage(payload)
if err2 != nil {
return nil, payload, err2
}
return encodedPayload, payload, nil
}

View file

@ -0,0 +1,44 @@
package payload
import (
"encoding/json"
"go.mau.fi/mautrix-gmessages/libgm/util"
)
func ReceiveMessages(rpcKey string) ([]byte, string, error) {
id := util.RandomUUIDv4()
data := []interface{}{
[]interface{}{
id,
nil,
nil,
nil,
nil,
rpcKey,
[]interface{}{
nil,
nil,
2023,
6,
8,
nil,
4,
nil,
6,
},
},
nil,
nil,
[]interface{}{
nil,
[]interface{}{},
},
}
jsonData, err := json.Marshal(data)
if err != nil {
return nil, "", err
}
return jsonData, id, nil
}

View file

@ -0,0 +1,33 @@
package payload
import (
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/crypto"
"go.mau.fi/mautrix-gmessages/libgm/util"
)
func RefreshPhoneRelay(rpcKey string) ([]byte, *binary.Container, error) {
decodedRpcKey, err1 := crypto.Base64DecodeStandard(rpcKey)
if err1 != nil {
return nil, nil, err1
}
payload := &binary.Container{
PhoneRelay: &binary.PhoneRelayBody{
Id: util.RandomUUIDv4(),
Bugle: "Bugle",
RpcKey: decodedRpcKey,
Date: &binary.Date{
Year: 2023,
Seq1: 6,
Seq2: 8,
Seq3: 4,
Seq4: 6,
},
},
}
encodedPayload, err2 := binary.EncodeProtoMessage(payload)
if err2 != nil {
return nil, payload, err2
}
return encodedPayload, payload, nil
}

View file

@ -0,0 +1,63 @@
package payload
import (
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/crypto"
"go.mau.fi/mautrix-gmessages/libgm/util"
)
func RegisterPhoneRelay(jwk *crypto.JWK) ([]byte, *binary.Container, error) {
id := util.RandomUUIDv4()
decodedPrivateKey, err2 := jwk.PrivKeyB64Bytes()
if err2 != nil {
return nil, nil, err2
}
jwk.PrivateBytes = decodedPrivateKey
uncompressedPublicKey, err3 := jwk.UncompressPubKey()
if err3 != nil {
return nil, nil, err3
}
var emptyByteArray []byte
crypto.EncodeValues(&emptyByteArray, crypto.SequenceOne)
crypto.EncodeValues(&emptyByteArray, crypto.SequenceTwo)
var copiedByteArray []byte
copiedByteArray = crypto.AppendByteSequence(copiedByteArray, emptyByteArray, uncompressedPublicKey)
for _, value := range uncompressedPublicKey {
copiedByteArray = crypto.HelperAppendBytes(copiedByteArray, value)
}
var emptyByteArray2 []byte
emptyByteArray2 = crypto.AppendBytes(emptyByteArray2, copiedByteArray[0:])
payloadData := &binary.Container{
PhoneRelay: &binary.PhoneRelayBody{
Id: id,
Bugle: "Bugle",
Date: &binary.Date{
Year: 2023,
Seq1: 6,
Seq2: 8,
Seq3: 4,
Seq4: 6,
},
},
BrowserDetails: &binary.BrowserDetails{
UserAgent: util.USER_AGENT,
SomeInt: 2,
SomeBool: true,
Os: util.OS,
},
PairDeviceData: &binary.PairDeviceData{
EcdsaKeys: &binary.ECDSAKeys{
ProtoVersion: 2,
EncryptedKeys: emptyByteArray2,
},
},
}
encoded, err4 := binary.EncodeProtoMessage(payloadData)
if err4 != nil {
return nil, payloadData, err4
}
return encoded, payloadData, nil
}

View file

@ -0,0 +1,42 @@
package payload
import "go.mau.fi/mautrix-gmessages/libgm/binary"
func NewMessageData(requestID string, encodedStr string, routingOpCode int64, msgType int64) *binary.MessageData {
return &binary.MessageData{
RequestId: requestID,
RoutingOpCode: routingOpCode,
EncodedData: encodedStr,
MsgTypeArr: &binary.MsgTypeArr{
EmptyArr: &binary.EmptyArr{},
MsgType: msgType,
},
}
}
func NewEncodedPayload(requestId string, opCode int64, encryptedData []byte, sessionId string) *binary.EncodedPayload {
return &binary.EncodedPayload{
RequestId: requestId,
Opcode: opCode,
EncryptedData: encryptedData,
SessionId: sessionId,
}
}
func NewAuthData(requestId string, rpcKey string, date *binary.Date) *binary.AuthMessage {
return &binary.AuthMessage{
RequestId: requestId,
RpcKey: rpcKey,
Date: date,
}
}
func NewSendMessage(pairedDevice *binary.Device, messageData *binary.MessageData, authData *binary.AuthMessage, ttl int64) *binary.SendMessage {
return &binary.SendMessage{
PairedDevice: pairedDevice,
MessageData: messageData,
AuthData: authData,
Ttl: ttl,
EmptyArr: &binary.EmptyArr{},
}
}

36
libgm/qr.go Normal file
View file

@ -0,0 +1,36 @@
package textgapi
import (
"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/util"
"github.com/skip2/go-qrcode"
)
func (p *Pairer) GenerateQRCodeData() (string, error) {
urlData := &binary.UrlData{
PairingKey: p.pairingKey,
AES_CTR_KEY_256: p.client.cryptor.AES_CTR_KEY_256,
SHA_256_KEY: p.client.cryptor.SHA_256_KEY,
}
encodedUrlData, err := binary.EncodeProtoMessage(urlData)
if err != nil {
return "", err
}
cData := crypto.Base64Encode(encodedUrlData)
return util.QR_CODE_URL + cData, nil
}
func (p *Pairer) GenerateQRCode(size int) (*events.QRCODE_UPDATED, error) {
data, err1 := p.GenerateQRCodeData()
if err1 != nil {
return nil, err1
}
png, err2 := qrcode.Encode(data, qrcode.Highest, size)
if err2 != nil {
return nil, err2
}
return events.NewQrCodeUpdated(png, size, size, data), nil
}

70
libgm/request.go Normal file
View file

@ -0,0 +1,70 @@
package textgapi
import (
"bytes"
"net/http"
"reflect"
"go.mau.fi/mautrix-gmessages/libgm/util"
)
func (c *Client) PostRequest(url string, payload []byte, headers interface{}) (*http.Response, error) {
req, err := http.NewRequest("POST", url, bytes.NewReader(payload))
if err != nil {
return nil, err
}
reqHeaders := &http.Header{}
SetHeaders(reqHeaders, headers)
req.Header = *reqHeaders
//c.Logger.Info().Any("headers", req.Header).Msg("POST Request Headers")
res, reqErr := c.http.Do(req)
if reqErr != nil {
return res, reqErr
}
return res, nil
}
func (c *Client) GetRequest(url string, headers interface{}) (*http.Response, error) {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
reqHeaders := &http.Header{}
SetHeaders(reqHeaders, headers)
req.Header = *reqHeaders
//c.Logger.Info().Any("headers", req.Header).Msg("GET Request Headers")
res, reqErr := c.http.Do(req)
if reqErr != nil {
return res, reqErr
}
return res, nil
}
func (c *Client) MakeRelayRequest(url string, body []byte) (*http.Response, error) {
req, err := http.NewRequest("POST", url, bytes.NewReader(body))
if err != nil {
return nil, err
}
util.BuildRelayHeaders(req, "application/x-protobuf", "*/*")
res, reqErr := c.http.Do(req)
//c.Logger.Info().Any("bodyLength", len(body)).Any("url", url).Any("headers", res.Request.Header).Msg("Relay Request Headers")
if reqErr != nil {
return res, reqErr
}
return res, nil
}
func SetHeaders(h *http.Header, headers interface{}) {
if headers == nil {
return
}
v := reflect.ValueOf(headers)
for i := 0; i < v.NumField(); i++ {
field := v.Type().Field(i)
value := v.Field(i).String()
if !v.Field(i).IsZero() {
h.Set(field.Tag.Get("header"), value)
}
}
}

16
libgm/response.go Normal file
View file

@ -0,0 +1,16 @@
package textgapi
import "go.mau.fi/mautrix-gmessages/libgm/binary"
func (c *Client) newMessagesResponse(responseData *Response) (*binary.FetchMessagesResponse, error) {
messages := &binary.FetchMessagesResponse{}
decryptErr := c.cryptor.DecryptAndDecodeData(responseData.Data.EncryptedData, messages)
if decryptErr != nil {
return nil, decryptErr
}
decryptErr = c.decryptImages(messages)
if decryptErr != nil {
return nil, decryptErr
}
return messages, nil
}

102
libgm/response_handler.go Normal file
View file

@ -0,0 +1,102 @@
package textgapi
import (
"fmt"
"log"
"sync"
)
type ResponseChan struct {
responses []*Response
receivedResponses int64
wg sync.WaitGroup
mu sync.Mutex
}
func (s *SessionHandler) addRequestToChannel(requestId string, opCode int64) {
instruction, notOk := s.client.instructions.GetInstruction(opCode)
if !notOk {
log.Fatal(notOk)
}
if msgMap, ok := s.requests[requestId]; ok {
responseChan := &ResponseChan{
responses: make([]*Response, 0, instruction.ExpectedResponses),
receivedResponses: 0,
wg: sync.WaitGroup{},
mu: sync.Mutex{},
}
msgMap[opCode] = responseChan
responseChan.wg.Add(int(instruction.ExpectedResponses))
responseChan.mu.Lock()
} else {
s.requests[requestId] = make(map[int64]*ResponseChan)
responseChan := &ResponseChan{
responses: make([]*Response, 0, instruction.ExpectedResponses),
receivedResponses: 0,
wg: sync.WaitGroup{},
mu: sync.Mutex{},
}
s.requests[requestId][opCode] = responseChan
responseChan.wg.Add(int(instruction.ExpectedResponses))
responseChan.mu.Lock()
}
}
func (s *SessionHandler) respondToRequestChannel(res *Response) {
requestId := res.Data.RequestId
reqChannel, ok := s.requests[requestId]
if !ok {
return
}
opCodeResponseChan, ok2 := reqChannel[res.Data.Opcode]
if !ok2 {
return
}
opCodeResponseChan.mu.Lock()
opCodeResponseChan.responses = append(opCodeResponseChan.responses, res)
s.client.Logger.Debug().Any("opcode", res.Data.Opcode).Msg("Got response")
instruction, ok3 := s.client.instructions.GetInstruction(res.Data.Opcode)
if opCodeResponseChan.receivedResponses >= instruction.ExpectedResponses {
s.client.Logger.Debug().Any("opcode", res.Data.Opcode).Msg("Ignoring opcode")
return
}
opCodeResponseChan.receivedResponses++
opCodeResponseChan.wg.Done()
if !ok3 {
log.Fatal(ok3)
opCodeResponseChan.mu.Unlock()
return
}
if opCodeResponseChan.receivedResponses >= instruction.ExpectedResponses {
delete(reqChannel, res.Data.Opcode)
if len(reqChannel) == 0 {
delete(s.requests, requestId)
}
}
opCodeResponseChan.mu.Unlock()
}
func (s *SessionHandler) WaitForResponse(requestId string, opCode int64) ([]*Response, error) {
requestResponses, ok := s.requests[requestId]
if !ok {
return nil, fmt.Errorf("no response channel found for request ID: %s (opcode: %v)", requestId, opCode)
}
responseChan, ok2 := requestResponses[opCode]
if !ok2 {
return nil, fmt.Errorf("no response channel found for opCode: %v (requestId: %s)", opCode, requestId)
}
// Unlock so responses can be received
responseChan.mu.Unlock()
// Wait for all responses to be received
responseChan.wg.Wait()
return responseChan.responses, nil
}

168
libgm/rpc.go Normal file
View file

@ -0,0 +1,168 @@
package textgapi
import (
"bufio"
"bytes"
"errors"
"io"
"log"
"net/http"
"os"
"go.mau.fi/mautrix-gmessages/libgm/events"
"go.mau.fi/mautrix-gmessages/libgm/util"
)
type RPC struct {
client *Client
http *http.Client
conn io.ReadCloser
rpcSessionId string
webAuthKey []byte
}
func (r *RPC) ListenReceiveMessages(payload []byte) {
req, err := http.NewRequest("POST", util.RECEIVE_MESSAGES, bytes.NewReader(payload))
if err != nil {
log.Fatalf("Error creating request: %v", err)
}
util.BuildRelayHeaders(req, "application/json+protobuf", "*/*")
resp, reqErr := r.http.Do(req)
//r.client.Logger.Info().Any("bodyLength", len(payload)).Any("url", util.RECEIVE_MESSAGES).Any("headers", resp.Request.Header).Msg("RPC Request Headers")
if reqErr != nil {
log.Fatalf("Error making request: %v", err)
}
r.conn = resp.Body
go r.startReadingData(resp.Body)
}
/*
The start of a message always begins with byte 44 (",")
If the message is parsable (after , has been removed) as an array of interfaces:
func (r *RPC) tryUnmarshalJSON(jsonData []byte, msgArr *[]interface{}) error {
err := json.Unmarshal(jsonData, &msgArr)
return err
}
then the message is complete and it should continue to the HandleRPCMsg function and it should also reset the buffer so that the next message can be received properly.
if it's not parsable, it should just append the received data to the buf and attempt to parse it until it's parsable. Because that would indicate that the full msg has been received
*/
func (r *RPC) startReadingData(rc io.ReadCloser) {
defer rc.Close()
reader := bufio.NewReader(rc)
buf := make([]byte, 2621440)
var accumulatedData []byte
for {
n, err := reader.Read(buf)
if err != nil {
if errors.Is(err, os.ErrClosed) {
r.client.Logger.Err(err).Msg("Closed body from server")
r.conn = nil
return
}
r.client.Logger.Err(err).Msg("Stopped reading data from server")
return
}
chunk := buf[:n]
if n <= 25 {
isHeartBeat := r.isHeartBeat(chunk)
if isHeartBeat {
r.client.Logger.Info().Any("heartBeat", isHeartBeat).Msg("Got heartbeat message")
}
isStartData := r.isStartRead(chunk)
if isStartData {
r.client.Logger.Info().Any("startRead", isHeartBeat).Msg("Got startReading message")
}
accumulatedData = []byte{}
continue
}
if len(accumulatedData) == 0 {
chunk = bytes.TrimPrefix(chunk, []byte{44})
}
accumulatedData = append(accumulatedData, chunk...)
var msgArr []interface{}
err = r.tryUnmarshalJSON(accumulatedData, &msgArr)
if err != nil {
//r.client.Logger.Err(err).Any("accumulated", string(accumulatedData)).Msg("Unable to unmarshal data, will wait for more data")
continue
}
accumulatedData = []byte{}
r.client.Logger.Info().Any("val", msgArr).Msg("MsgArr")
go r.HandleRPCMsg(msgArr)
}
}
func (r *RPC) isStartRead(data []byte) bool {
return string(data) == "[[[null,null,null,[]]"
}
func (r *RPC) isHeartBeat(data []byte) bool {
return string(data) == ",[null,null,[]]"
}
/*
func (r *RPC) startReadingData(rc io.ReadCloser) {
defer rc.Close()
reader := bufio.NewReader(rc)
buf := make([]byte, 5242880)
for {
n, err := reader.Read(buf)
if err != nil {
if errors.Is(err, os.ErrClosed) {
r.client.Logger.Err(err).Msg("Closed body from server")
r.conn = nil
return
}
r.client.Logger.Err(err).Msg("Stopped reading data from server")
return
}
chunk := buf[:n]
var msgArr []interface{}
isComplete := r.tryUnmarshalJSON(chunk, &msgArr)
r.client.Logger.Info().Any("val", chunk[0] == 44).Any("isComplete", string(chunk)).Msg("is Start?")
go r.HandleRPCMsg(buf[:n])
}
}
*/
func (r *RPC) CloseConnection() {
if r.conn != nil {
r.client.Logger.Debug().Msg("Attempting to connection...")
r.conn.Close()
r.conn = nil
}
}
func (r *RPC) sendMessageRequest(url string, payload []byte) (*http.Response, error) {
req, err := http.NewRequest("POST", url, bytes.NewReader(payload))
if err != nil {
log.Fatalf("Error creating request: %v", err)
}
util.BuildRelayHeaders(req, "application/json+protobuf", "*/*")
resp, reqErr := r.client.http.Do(req)
//r.client.Logger.Info().Any("bodyLength", len(payload)).Any("url", url).Any("headers", resp.Request.Header).Msg("RPC Request Headers")
if reqErr != nil {
log.Fatalf("Error making request: %v", err)
}
return resp, reqErr
}
func (r *RPC) sendInitialData() error {
sessionResponse, err := r.client.Session.SetActiveSession()
if err != nil {
return err
}
conversationList, convErr := r.client.Conversations.List(25)
if convErr != nil {
return convErr
}
evtData := events.NewClientReady(sessionResponse, conversationList)
r.client.triggerEvent(evtData)
r.client.sessionHandler.startAckInterval()
return nil
}

66
libgm/session.go Normal file
View file

@ -0,0 +1,66 @@
package textgapi
import "go.mau.fi/mautrix-gmessages/libgm/util"
type Session struct {
client *Client
prepareNewSession prepareNewSession
newSession newSession
}
func (s *Session) SetActiveSession() (*util.SessionResponse, error) {
s.client.sessionHandler.ResetSessionId()
prepareResponses, prepareSessionErr := s.prepareNewSession.Execute()
if prepareSessionErr != nil {
return nil, prepareSessionErr
}
newSessionResponses, newSessionErr := s.newSession.Execute()
if newSessionErr != nil {
return nil, newSessionErr
}
sessionResponse, processFail := s.client.processSessionResponse(prepareResponses, newSessionResponses)
if processFail != nil {
return nil, processFail
}
s.client.cache.SetSettings(sessionResponse.Settings)
return sessionResponse, nil
}
type prepareNewSession struct {
client *Client
}
func (p *prepareNewSession) Execute() ([]*Response, error) {
instruction, _ := p.client.instructions.GetInstruction(PREPARE_NEW_SESSION_OPCODE)
sentRequestId, _ := p.client.createAndSendRequest(instruction.Opcode, p.client.ttl, false, nil)
responses, err := p.client.sessionHandler.WaitForResponse(sentRequestId, instruction.Opcode)
if err != nil {
return nil, err
}
return responses, nil
}
type newSession struct {
client *Client
}
func (n *newSession) Execute() ([]*Response, error) {
instruction, _ := n.client.instructions.GetInstruction(NEW_SESSION_OPCODE)
sentRequestId, _ := n.client.createAndSendRequest(instruction.Opcode, 0, true, nil)
responses, err := n.client.sessionHandler.WaitForResponse(sentRequestId, instruction.Opcode)
if err != nil {
return nil, err
}
// Rest of the processing...
return responses, nil
}

216
libgm/session_handler.go Normal file
View file

@ -0,0 +1,216 @@
package textgapi
import (
"encoding/json"
"fmt"
"log"
"time"
"golang.org/x/exp/slices"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/crypto"
"go.mau.fi/mautrix-gmessages/libgm/json_proto"
"go.mau.fi/mautrix-gmessages/libgm/payload"
"go.mau.fi/mautrix-gmessages/libgm/util"
)
type Response struct {
client *Client
ResponseId string
RoutingOpCode int64
Data *binary.EncodedResponse // base64 encoded (decode -> protomessage)
StartExecute string
FinishExecute string
DevicePair *DevicePair
}
type SessionHandler struct {
client *Client
requests map[string]map[int64]*ResponseChan
ackMap []string
ackTicker *time.Ticker
sessionId string
responseTimeout time.Duration
}
func (s *SessionHandler) SetResponseTimeout(milliSeconds int) {
s.responseTimeout = time.Duration(milliSeconds) * time.Millisecond
}
func (s *SessionHandler) ResetSessionId() {
s.sessionId = util.RandomUUIDv4()
}
func (c *Client) createAndSendRequest(instructionId int64, ttl int64, newSession bool, encryptedProtoMessage protoreflect.Message) (string, error) {
requestId := util.RandomUUIDv4()
instruction, ok := c.instructions.GetInstruction(instructionId)
if !ok {
return "", fmt.Errorf("failed to get instruction: %v does not exist", instructionId)
}
if newSession {
requestId = c.sessionHandler.sessionId
}
var encryptedData []byte
var encryptErr error
if encryptedProtoMessage != nil {
encryptedData, encryptErr = c.EncryptPayloadData(encryptedProtoMessage)
if encryptErr != nil {
return "", fmt.Errorf("failed to encrypt payload data for opcode: %v", instructionId)
}
c.Logger.Info().Any("encryptedData", encryptedData).Msg("Sending request with encrypted data")
}
encodedData := payload.NewEncodedPayload(requestId, instruction.Opcode, encryptedData, c.sessionHandler.sessionId)
encodedStr, encodeErr := crypto.EncodeProtoB64(encodedData)
if encodeErr != nil {
log.Fatalf("Failed to encode data: %v", encodeErr)
}
messageData := payload.NewMessageData(requestId, encodedStr, instruction.RoutingOpCode, instruction.MsgType)
authMessage := payload.NewAuthData(requestId, c.rpcKey, &binary.Date{Year: 2023, Seq1: 6, Seq2: 8, Seq3: 4, Seq4: 6})
sendMessage := payload.NewSendMessage(c.devicePair.Mobile, messageData, authMessage, ttl)
sentRequestId, reqErr := c.sessionHandler.completeSendMessage(encodedData.RequestId, instruction.Opcode, sendMessage)
if reqErr != nil {
return "", fmt.Errorf("failed to send message request for opcode: %v", instructionId)
}
return sentRequestId, nil
}
func (s *SessionHandler) completeSendMessage(requestId string, opCode int64, msg *binary.SendMessage) (string, error) {
jsonData, err := s.toJSON(msg.ProtoReflect())
if err != nil {
return "", err
}
//s.client.Logger.Debug().Any("payload", string(jsonData)).Msg("Sending message request")
s.addRequestToChannel(requestId, opCode)
_, reqErr := s.client.rpc.sendMessageRequest(util.SEND_MESSAGE, jsonData)
if reqErr != nil {
return "", reqErr
}
return requestId, nil
}
func (s *SessionHandler) toJSON(message protoreflect.Message) ([]byte, error) {
interfaceArr, err := json_proto.Serialize(message)
if err != nil {
return nil, err
}
jsonData, jsonErr := json.Marshal(interfaceArr)
if jsonErr != nil {
return nil, jsonErr
}
return jsonData, nil
}
func (s *SessionHandler) addResponseAck(responseId string) {
hasResponseId := slices.Contains(s.ackMap, responseId)
if !hasResponseId {
s.ackMap = append(s.ackMap, responseId)
}
}
func (s *SessionHandler) startAckInterval() {
if s.ackTicker != nil {
s.ackTicker.Stop()
}
ticker := time.NewTicker(5 * time.Second)
s.ackTicker = ticker
go func() {
for range ticker.C {
s.sendAckRequest()
}
}()
}
func (s *SessionHandler) sendAckRequest() {
if len(s.ackMap) <= 0 {
return
}
reqId := util.RandomUUIDv4()
ackMessagePayload := &binary.AckMessagePayload{
AuthData: &binary.AuthMessage{
RequestId: reqId,
RpcKey: s.client.rpcKey,
Date: &binary.Date{Year: 2023, Seq1: 6, Seq2: 8, Seq3: 4, Seq4: 6},
},
EmptyArr: &binary.EmptyArr{},
NoClue: nil,
}
dataArray, err := json_proto.Serialize(ackMessagePayload.ProtoReflect())
if err != nil {
log.Fatal(err)
}
ackMessages := make([][]interface{}, 0)
for _, reqId := range s.ackMap {
ackMessageData := &binary.AckMessageData{RequestId: reqId, Device: s.client.devicePair.Browser}
ackMessageDataArr, err := json_proto.Serialize(ackMessageData.ProtoReflect())
if err != nil {
log.Fatal(err)
}
ackMessages = append(ackMessages, ackMessageDataArr)
s.ackMap = util.RemoveFromSlice(s.ackMap, reqId)
}
dataArray = append(dataArray, ackMessages)
jsonData, jsonErr := json.Marshal(dataArray)
if jsonErr != nil {
log.Fatal(err)
}
_, err = s.client.rpc.sendMessageRequest(util.ACK_MESSAGES, jsonData)
if err != nil {
log.Fatal(err)
}
log.Println("[ACK] Sent Request")
}
func (s *SessionHandler) NewResponse(response *binary.RPCResponse) (*Response, error) {
//s.client.Logger.Debug().Any("rpcResponse", response).Msg("Raw rpc response")
decodedData, err := crypto.DecodeEncodedResponse(response.Data.EncodedData)
if err != nil {
log.Fatal(err)
return nil, err
}
return &Response{
client: s.client,
ResponseId: response.Data.RequestId,
RoutingOpCode: response.Data.RoutingOpCode,
StartExecute: response.Data.Ts1,
FinishExecute: response.Data.Ts2,
DevicePair: &DevicePair{
Mobile: response.Data.Mobile,
Browser: response.Data.Browser,
},
Data: decodedData,
}, nil
}
func (r *Response) decryptData() (proto.Message, error) {
if r.Data.EncryptedData != nil {
instruction, ok := r.client.instructions.GetInstruction(r.Data.Opcode)
if !ok {
return nil, fmt.Errorf("failed to decrypt data for unknown opcode: %v", r.Data.Opcode)
}
decryptedBytes, errDecrypt := instruction.cryptor.Decrypt(r.Data.EncryptedData)
if errDecrypt != nil {
return nil, errDecrypt
}
//os.WriteFile("opcode_"+strconv.Itoa(int(instruction.Opcode))+".bin", decryptedBytes, os.ModePerm)
protoMessageData := instruction.DecryptedProtoMessage.ProtoReflect().Type().New().Interface()
decodeProtoErr := binary.DecodeProtoMessage(decryptedBytes, protoMessageData)
if decodeProtoErr != nil {
return nil, decodeProtoErr
}
return protoMessageData, nil
}
return nil, fmt.Errorf("no encrypted data to decrypt for requestId: %s", r.Data.RequestId)
}

9
libgm/util/constants.go Normal file
View file

@ -0,0 +1,9 @@
package util
var GOOG_API_KEY = "AIzaSyCA4RsOZUFrm9whhtGosPlJLmVPnfSHKz8"
var USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36"
var OS = "Linux"
var X_USER_AGENT = "grpc-web-javascript/0.1"
var QR_CODE_URL = "https://support.google.com/messages/?p=web_computer#?c="
var TENOR_API_KEY = "YR0F99AJ65AV"

12
libgm/util/errors.go Normal file
View file

@ -0,0 +1,12 @@
package util
import "fmt"
type InstructionNotFound struct {
Opcode int64
}
func (e *InstructionNotFound) Error() string {
return fmt.Sprintf("Could not find instruction for opcode %d", e.Opcode)
}

135
libgm/util/func.go Normal file
View file

@ -0,0 +1,135 @@
package util
import (
crand "crypto/rand"
"encoding/hex"
"fmt"
"math/rand"
"net/http"
"time"
"github.com/nu7hatch/gouuid"
)
var Charset = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")
func RandStr(length int) string {
b := make([]rune, length)
for i := range b {
b[i] = Charset[rand.Intn(len(Charset))]
}
return string(b)
}
func GenerateImageId() string {
part1 := RandomUUIDv4()
part2 := RandStr(25)
return part1 + "/" + part2
}
func GenerateTmpId() string {
src := rand.NewSource(time.Now().UnixNano())
r := rand.New(src)
randNum := r.Int63n(1e12)
return fmt.Sprintf("tmp_%012d", randNum)
}
func ParseTimestamp(unixTs int64) time.Time {
seconds := unixTs / int64(time.Second / time.Microsecond)
nanoseconds := (unixTs % int64(time.Second / time.Microsecond)) * int64(time.Microsecond / time.Nanosecond)
return time.Unix(seconds, nanoseconds).UTC()
}
func RandomHex(n int) string {
bytes := make([]byte, n)
crand.Read(bytes)
return hex.EncodeToString(bytes)
}
func RandomUUIDv4() string {
id, _ := uuid.NewV4()
return id.String()
}
func RemoveFromSlice(s []string, v string) []string {
newS := []string{}
for _, i := range s {
if i != v {
newS = append(newS, i)
}
}
return newS
}
func BuildRelayHeaders(req *http.Request, contentType string, accept string) {
req.Header.Add("host", "instantmessaging-pa.googleapis.com")
req.Header.Add("connection", "keep-alive")
req.Header.Add("sec-ch-ua", "\"Google Chrome\";v=\"113\", \"Chromium\";v=\"113\", \"Not-A.Brand\";v=\"24\"")
req.Header.Add("x-user-agent", X_USER_AGENT)
req.Header.Add("x-goog-api-key", GOOG_API_KEY)
if len(contentType) > 0 {
req.Header.Add("content-type", contentType)
}
req.Header.Add("sec-ch-ua-mobile", "?0")
req.Header.Add("user-agent", USER_AGENT)
req.Header.Add("sec-ch-ua-platform", "\""+OS+"\"")
req.Header.Add("accept", accept)
req.Header.Add("origin", "https://messages.google.com")
req.Header.Add("sec-fetch-site", "cross-site")
req.Header.Add("sec-fetch-mode", "cors")
req.Header.Add("sec-fetch-dest", "empty")
req.Header.Add("referer", "https://messages.google.com/")
req.Header.Add("accept-language", "en-US,en;q=0.9")
}
func BuildUploadHeaders(req *http.Request, metadata string) {
req.Header.Add("host", "instantmessaging-pa.googleapis.com")
req.Header.Add("connection", "keep-alive")
req.Header.Add("x-goog-download-metadata", metadata)
req.Header.Add("sec-ch-ua", "\"Google Chrome\";v=\"113\", \"Chromium\";v=\"113\", \"Not-A.Brand\";v=\"24\"")
req.Header.Add("sec-ch-ua-mobile", "?0")
req.Header.Add("user-agent", USER_AGENT)
req.Header.Add("sec-ch-ua-platform", "\""+OS+"\"")
req.Header.Add("accept", "*/*")
req.Header.Add("origin", "https://messages.google.com")
req.Header.Add("sec-fetch-site", "cross-site")
req.Header.Add("sec-fetch-mode", "cors")
req.Header.Add("sec-fetch-dest", "empty")
req.Header.Add("referer", "https://messages.google.com/")
req.Header.Add("accept-encoding", "gzip, deflate, br")
req.Header.Add("accept-language", "en-US,en;q=0.9")
}
func NewMediaUploadHeaders(imageSize string, command string, uploadOffset string, imageContentType string, protocol string) *http.Header {
headers := &http.Header{}
headers.Add("host", "instantmessaging-pa.googleapis.com")
headers.Add("connection", "keep-alive")
headers.Add("sec-ch-ua", "\"Google Chrome\";v=\"113\", \"Chromium\";v=\"113\", \"Not-A.Brand\";v=\"24\"")
if protocol != "" {
headers.Add("x-goog-upload-protocol", protocol)
}
headers.Add("x-goog-upload-header-content-length", imageSize)
headers.Add("sec-ch-ua-mobile", "?0")
headers.Add("user-agent", USER_AGENT)
if imageContentType != "" {
headers.Add("x-goog-upload-header-content-type", imageContentType)
}
headers.Add("content-type", "application/x-www-form-urlencoded;charset=UTF-8")
if command != "" {
headers.Add("x-goog-upload-command", command)
}
if uploadOffset != "" {
headers.Add("x-goog-upload-offset", uploadOffset)
}
headers.Add("sec-ch-ua-platform", "\""+OS+"\"")
headers.Add("accept", "*/*")
headers.Add("origin", "https://messages.google.com")
headers.Add("sec-fetch-site", "cross-site")
headers.Add("sec-fetch-mode", "cors")
headers.Add("sec-fetch-dest", "empty")
headers.Add("referer", "https://messages.google.com/")
headers.Add("accept-encoding", "gzip, deflate, br")
headers.Add("accept-language", "en-US,en;q=0.9")
return headers
}

23
libgm/util/paths.go Normal file
View file

@ -0,0 +1,23 @@
package util
var MESSAGES_GOOGLE_BASE_URL = "https://messages.google.com"
var MESSAGES_GOOGLE_AUTHENTICATION = MESSAGES_GOOGLE_BASE_URL+"/web/authentication"
var MESSAGES_GOOGLE_TIMESOURCE = MESSAGES_GOOGLE_BASE_URL+"/web/timesource"
var INSTANT_MESSAGING = "https://instantmessaging-pa.googleapis.com"
var UPLOAD_MEDIA = INSTANT_MESSAGING+"/upload"
var PAIRING = INSTANT_MESSAGING+"/$rpc/google.internal.communications.instantmessaging.v1.Pairing"
var REGISTER_PHONE_RELAY = PAIRING+"/RegisterPhoneRelay"
var REFRESH_PHONE_RELAY = PAIRING+"/RefreshPhoneRelay"
var GET_WEB_ENCRYPTION_KEY = PAIRING+"/GetWebEncryptionKey"
var MESSAGING = INSTANT_MESSAGING+"/$rpc/google.internal.communications.instantmessaging.v1.Messaging"
var RECEIVE_MESSAGES = MESSAGING+"/ReceiveMessages"
var SEND_MESSAGE = MESSAGING+"/SendMessage"
var ACK_MESSAGES = MESSAGING+"/AckMessages"
var TENOR_BASE_URL = "https://api.tenor.com/v1"
var TENOR_SEARCH_GIF = TENOR_BASE_URL+"/search"

111
libgm/util/structs.go Normal file
View file

@ -0,0 +1,111 @@
package util
import "go.mau.fi/mautrix-gmessages/libgm/binary"
type SessionResponse struct {
Success bool
Settings *binary.Settings
}
type Headers struct {
Host string `json:"host,omitempty" header:"host"`
Connection string `json:"connection,omitempty" header:"connection"`
SecChUa string `json:"sec-ch-ua,omitempty" header:"sec-ch-ua"`
SecChUaMobile string `json:"sec-ch-ua-mobile,omitempty" header:"sec-ch-ua-mobile"`
SecChUaPlatform string `json:"sec-ch-ua-platform,omitempty" header:"sec-ch-ua-platform"`
UpgradeInsecureRequests string `json:"upgrade-insecure-requests,omitempty" header:"upgrade-insecure-requests"`
UserAgent string `json:"user-agent,omitempty" header:"user-agent"`
Accept string `json:"accept,omitempty" header:"accept"`
Cookie string `json:"cookie,omitempty" header:"cookie"`
Referer string `json:"referer,omitempty" header:"referer"`
SecFetchSite string `json:"sec-fetch-site,omitempty" header:"sec-fetch-site"`
SecFetchMode string `json:"sec-fetch-mode,omitempty" header:"sec-fetch-mode"`
SecFetchUser string `json:"sec-fetch-user,omitempty" header:"sec-fetch-user"`
SecFetchDest string `json:"sec-fetch-dest,omitempty" header:"sec-fetch-dest"`
AcceptEncoding string `json:"accept-encoding,omitempty" header:"accept-encoding"`
AcceptLanguage string `json:"accept-language,omitempty" header:"accept-language"`
}
func (h *Headers) Build() {
h.Connection = "keep-alive"
h.SecChUa = `"Google Chrome";v="113", "Chromium";v="113", "Not-A.Brand";v="24"`
h.SecChUaMobile = "?0"
h.SecChUaPlatform = `"Linux"`
h.UpgradeInsecureRequests = "1"
h.UserAgent = USER_AGENT
h.Accept = `text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7`
h.SecFetchSite = "none"
h.SecFetchMode = "navigate"
h.SecFetchUser = "?1"
h.SecFetchDest = "document"
h.AcceptEncoding = "gzip, deflate, br"
h.AcceptLanguage = "en-US,en;q=0.9"
}
func (h *Headers) SetReferer(referer string) {
h.Referer = referer
}
func (h *Headers) SetSecFetchSite(val string) {
h.SecFetchSite = val
}
func (h *Headers) SetSecFetchUser(val string) {
h.SecFetchUser = val
}
func (h *Headers) SetSecFetchDest(val string) {
h.SecFetchDest = val
}
func (h *Headers) SetUpgradeInsecureRequests(val string) {
h.UpgradeInsecureRequests = val
}
func (h *Headers) SetAccept(val string) {
h.Accept = val
}
type RelayHeaders struct {
Host string `json:"host,omitempty"`
Connection string `json:"connection,omitempty"`
SecChUa string `json:"sec-ch-ua,omitempty"`
XUserAgent string `json:"x-user-agent,omitempty"`
XGoogAPIKey string `json:"x-goog-api-key,omitempty"`
ContentType string `json:"content-type,omitempty"`
SecChUaMobile string `json:"sec-ch-ua-mobile,omitempty"`
UserAgent string `json:"user-agent,omitempty"`
SecChUaPlatform string `json:"sec-ch-ua-platform,omitempty"`
Accept string `json:"accept,omitempty"`
Origin string `json:"origin,omitempty"`
XClientData string `json:"x-client-data,omitempty"`
SecFetchSite string `json:"sec-fetch-site,omitempty"`
SecFetchMode string `json:"sec-fetch-mode,omitempty"`
SecFetchDest string `json:"sec-fetch-dest,omitempty"`
Referer string `json:"referer,omitempty"`
AcceptEncoding string `json:"accept-encoding,omitempty"`
AcceptLanguage string `json:"accept-language,omitempty"`
}
type MediaUploadHeaders struct {
Host string `json:"host"`
Connection string `json:"connection"`
SecChUa string `json:"sec-ch-ua"`
XGoogUploadProtocol string `json:"x-goog-upload-protocol"`
XGoogUploadHeaderContentLength string `json:"x-goog-upload-header-content-length"`
SecChUaMobile string `json:"sec-ch-ua-mobile"`
UserAgent string `json:"user-agent"`
XGoogUploadHeaderContentType string `json:"x-goog-upload-header-content-type"`
ContentType string `json:"content-type"`
XGoogUploadCommand string `json:"x-goog-upload-command"`
SecChUaPlatform string `json:"sec-ch-ua-platform"`
Accept string `json:"accept"`
Origin string `json:"origin"`
XClientData string `json:"x-client-data"`
SecFetchSite string `json:"sec-fetch-site"`
SecFetchMode string `json:"sec-fetch-mode"`
SecFetchDest string `json:"sec-fetch-dest"`
Referer string `json:"referer"`
AcceptEncoding string `json:"accept-encoding"`
AcceptLanguage string `json:"accept-language"`
}