From 2ed658df2cf18d19272c1dccd8589cf209bb0e17 Mon Sep 17 00:00:00 2001 From: atavism Date: Wed, 20 Mar 2024 13:04:00 -0700 Subject: [PATCH 01/10] remove protobuf api changes --- pro/client/api.pb.go | 1035 ------------------------------------------ pro/client/api.proto | 74 --- pro/client/client.go | 46 -- 3 files changed, 1155 deletions(-) delete mode 100644 pro/client/api.pb.go delete mode 100644 pro/client/api.proto diff --git a/pro/client/api.pb.go b/pro/client/api.pb.go deleted file mode 100644 index 188a1be13..000000000 --- a/pro/client/api.pb.go +++ /dev/null @@ -1,1035 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.31.0 -// protoc v4.24.3 -// source: pro/client/api.proto - -package client - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - structpb "google.golang.org/protobuf/types/known/structpb" - 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 Provider int32 - -const ( - Provider_PROVIDER_UNSET Provider = 0 - Provider_STRIPE Provider = 1 - Provider_FREEKASSA Provider = 2 -) - -// Enum value maps for Provider. -var ( - Provider_name = map[int32]string{ - 0: "PROVIDER_UNSET", - 1: "STRIPE", - 2: "FREEKASSA", - } - Provider_value = map[string]int32{ - "PROVIDER_UNSET": 0, - "STRIPE": 1, - "FREEKASSA": 2, - } -) - -func (x Provider) Enum() *Provider { - p := new(Provider) - *p = x - return p -} - -func (x Provider) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (Provider) Descriptor() protoreflect.EnumDescriptor { - return file_pro_client_api_proto_enumTypes[0].Descriptor() -} - -func (Provider) Type() protoreflect.EnumType { - return &file_pro_client_api_proto_enumTypes[0] -} - -func (x Provider) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Use Provider.Descriptor instead. -func (Provider) EnumDescriptor() ([]byte, []int) { - return file_pro_client_api_proto_rawDescGZIP(), []int{0} -} - -type ProPlan struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` - BestValue bool `protobuf:"varint,3,opt,name=bestValue,proto3" json:"bestValue,omitempty"` - UsdPrice int64 `protobuf:"varint,4,opt,name=usdPrice,proto3" json:"usdPrice,omitempty"` - Price map[string]int64 `protobuf:"bytes,5,rep,name=price,proto3" json:"price,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` - ExpectedMonthlyPrice map[string]int64 `protobuf:"bytes,6,rep,name=expectedMonthlyPrice,proto3" json:"expectedMonthlyPrice,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` - TotalCostBilledOneTime string `protobuf:"bytes,7,opt,name=totalCostBilledOneTime,proto3" json:"totalCostBilledOneTime,omitempty"` - OneMonthCost string `protobuf:"bytes,8,opt,name=oneMonthCost,proto3" json:"oneMonthCost,omitempty"` - TotalCost string `protobuf:"bytes,9,opt,name=totalCost,proto3" json:"totalCost,omitempty"` - FormattedBonus string `protobuf:"bytes,10,opt,name=formattedBonus,proto3" json:"formattedBonus,omitempty"` - RenewalText string `protobuf:"bytes,11,opt,name=renewalText,proto3" json:"renewalText,omitempty"` -} - -func (x *ProPlan) Reset() { - *x = ProPlan{} - if protoimpl.UnsafeEnabled { - mi := &file_pro_client_api_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ProPlan) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ProPlan) ProtoMessage() {} - -func (x *ProPlan) ProtoReflect() protoreflect.Message { - mi := &file_pro_client_api_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 ProPlan.ProtoReflect.Descriptor instead. -func (*ProPlan) Descriptor() ([]byte, []int) { - return file_pro_client_api_proto_rawDescGZIP(), []int{0} -} - -func (x *ProPlan) GetId() string { - if x != nil { - return x.Id - } - return "" -} - -func (x *ProPlan) GetDescription() string { - if x != nil { - return x.Description - } - return "" -} - -func (x *ProPlan) GetBestValue() bool { - if x != nil { - return x.BestValue - } - return false -} - -func (x *ProPlan) GetUsdPrice() int64 { - if x != nil { - return x.UsdPrice - } - return 0 -} - -func (x *ProPlan) GetPrice() map[string]int64 { - if x != nil { - return x.Price - } - return nil -} - -func (x *ProPlan) GetExpectedMonthlyPrice() map[string]int64 { - if x != nil { - return x.ExpectedMonthlyPrice - } - return nil -} - -func (x *ProPlan) GetTotalCostBilledOneTime() string { - if x != nil { - return x.TotalCostBilledOneTime - } - return "" -} - -func (x *ProPlan) GetOneMonthCost() string { - if x != nil { - return x.OneMonthCost - } - return "" -} - -func (x *ProPlan) GetTotalCost() string { - if x != nil { - return x.TotalCost - } - return "" -} - -func (x *ProPlan) GetFormattedBonus() string { - if x != nil { - return x.FormattedBonus - } - return "" -} - -func (x *ProPlan) GetRenewalText() string { - if x != nil { - return x.RenewalText - } - return "" -} - -type PlansResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Plans []*ProPlan `protobuf:"bytes,1,rep,name=plans,proto3" json:"plans,omitempty"` -} - -func (x *PlansResponse) Reset() { - *x = PlansResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_pro_client_api_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PlansResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PlansResponse) ProtoMessage() {} - -func (x *PlansResponse) ProtoReflect() protoreflect.Message { - mi := &file_pro_client_api_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 PlansResponse.ProtoReflect.Descriptor instead. -func (*PlansResponse) Descriptor() ([]byte, []int) { - return file_pro_client_api_proto_rawDescGZIP(), []int{1} -} - -func (x *PlansResponse) GetPlans() []*ProPlan { - if x != nil { - return x.Plans - } - return nil -} - -type ProPaymentProvider struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Data map[string]string `protobuf:"bytes,2,rep,name=data,proto3" json:"data,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` -} - -func (x *ProPaymentProvider) Reset() { - *x = ProPaymentProvider{} - if protoimpl.UnsafeEnabled { - mi := &file_pro_client_api_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ProPaymentProvider) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ProPaymentProvider) ProtoMessage() {} - -func (x *ProPaymentProvider) ProtoReflect() protoreflect.Message { - mi := &file_pro_client_api_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 ProPaymentProvider.ProtoReflect.Descriptor instead. -func (*ProPaymentProvider) Descriptor() ([]byte, []int) { - return file_pro_client_api_proto_rawDescGZIP(), []int{2} -} - -func (x *ProPaymentProvider) GetName() string { - if x != nil { - return x.Name - } - return "" -} - -func (x *ProPaymentProvider) GetData() map[string]string { - if x != nil { - return x.Data - } - return nil -} - -type ProPaymentMethod struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Method string `protobuf:"bytes,1,opt,name=method,proto3" json:"method,omitempty"` - Providers []*ProPaymentProvider `protobuf:"bytes,2,rep,name=providers,proto3" json:"providers,omitempty"` -} - -func (x *ProPaymentMethod) Reset() { - *x = ProPaymentMethod{} - if protoimpl.UnsafeEnabled { - mi := &file_pro_client_api_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ProPaymentMethod) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ProPaymentMethod) ProtoMessage() {} - -func (x *ProPaymentMethod) ProtoReflect() protoreflect.Message { - mi := &file_pro_client_api_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 ProPaymentMethod.ProtoReflect.Descriptor instead. -func (*ProPaymentMethod) Descriptor() ([]byte, []int) { - return file_pro_client_api_proto_rawDescGZIP(), []int{3} -} - -func (x *ProPaymentMethod) GetMethod() string { - if x != nil { - return x.Method - } - return "" -} - -func (x *ProPaymentMethod) GetProviders() []*ProPaymentProvider { - if x != nil { - return x.Providers - } - return nil -} - -type PaymentMethodsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Providers map[string]*structpb.ListValue `protobuf:"bytes,1,rep,name=providers,proto3" json:"providers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` -} - -func (x *PaymentMethodsResponse) Reset() { - *x = PaymentMethodsResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_pro_client_api_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PaymentMethodsResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PaymentMethodsResponse) ProtoMessage() {} - -func (x *PaymentMethodsResponse) ProtoReflect() protoreflect.Message { - mi := &file_pro_client_api_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 PaymentMethodsResponse.ProtoReflect.Descriptor instead. -func (*PaymentMethodsResponse) Descriptor() ([]byte, []int) { - return file_pro_client_api_proto_rawDescGZIP(), []int{4} -} - -func (x *PaymentMethodsResponse) GetProviders() map[string]*structpb.ListValue { - if x != nil { - return x.Providers - } - return nil -} - -type PaymentRedirectRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Plan string `protobuf:"bytes,1,opt,name=plan,proto3" json:"plan,omitempty"` - Provider string `protobuf:"bytes,2,opt,name=provider,proto3" json:"provider,omitempty"` - Currency string `protobuf:"bytes,3,opt,name=currency,proto3" json:"currency,omitempty"` - Email string `protobuf:"bytes,4,opt,name=email,proto3" json:"email,omitempty"` - DeviceName string `protobuf:"bytes,5,opt,name=deviceName,proto3" json:"deviceName,omitempty"` - CountryCode string `protobuf:"bytes,6,opt,name=countryCode,proto3" json:"countryCode,omitempty"` -} - -func (x *PaymentRedirectRequest) Reset() { - *x = PaymentRedirectRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_pro_client_api_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PaymentRedirectRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PaymentRedirectRequest) ProtoMessage() {} - -func (x *PaymentRedirectRequest) ProtoReflect() protoreflect.Message { - mi := &file_pro_client_api_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 PaymentRedirectRequest.ProtoReflect.Descriptor instead. -func (*PaymentRedirectRequest) Descriptor() ([]byte, []int) { - return file_pro_client_api_proto_rawDescGZIP(), []int{5} -} - -func (x *PaymentRedirectRequest) GetPlan() string { - if x != nil { - return x.Plan - } - return "" -} - -func (x *PaymentRedirectRequest) GetProvider() string { - if x != nil { - return x.Provider - } - return "" -} - -func (x *PaymentRedirectRequest) GetCurrency() string { - if x != nil { - return x.Currency - } - return "" -} - -func (x *PaymentRedirectRequest) GetEmail() string { - if x != nil { - return x.Email - } - return "" -} - -func (x *PaymentRedirectRequest) GetDeviceName() string { - if x != nil { - return x.DeviceName - } - return "" -} - -func (x *PaymentRedirectRequest) GetCountryCode() string { - if x != nil { - return x.CountryCode - } - return "" -} - -type PaymentRedirectResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Redirect string `protobuf:"bytes,1,opt,name=redirect,proto3" json:"redirect,omitempty"` -} - -func (x *PaymentRedirectResponse) Reset() { - *x = PaymentRedirectResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_pro_client_api_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PaymentRedirectResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PaymentRedirectResponse) ProtoMessage() {} - -func (x *PaymentRedirectResponse) ProtoReflect() protoreflect.Message { - mi := &file_pro_client_api_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 PaymentRedirectResponse.ProtoReflect.Descriptor instead. -func (*PaymentRedirectResponse) Descriptor() ([]byte, []int) { - return file_pro_client_api_proto_rawDescGZIP(), []int{6} -} - -func (x *PaymentRedirectResponse) GetRedirect() string { - if x != nil { - return x.Redirect - } - return "" -} - -type PurchaseRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Provider Provider `protobuf:"varint,1,opt,name=provider,proto3,enum=Provider" json:"provider,omitempty"` - Email string `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"` - Plan string `protobuf:"bytes,3,opt,name=plan,proto3" json:"plan,omitempty"` - CardNumber string `protobuf:"bytes,4,opt,name=cardNumber,proto3" json:"cardNumber,omitempty"` - ExpDate string `protobuf:"bytes,5,opt,name=expDate,proto3" json:"expDate,omitempty"` - Cvc string `protobuf:"bytes,6,opt,name=cvc,proto3" json:"cvc,omitempty"` - Currency string `protobuf:"bytes,7,opt,name=currency,proto3" json:"currency,omitempty"` - DeviceName string `protobuf:"bytes,8,opt,name=deviceName,proto3" json:"deviceName,omitempty"` - StripePublicKey string `protobuf:"bytes,9,opt,name=stripePublicKey,proto3" json:"stripePublicKey,omitempty"` - StripeEmail string `protobuf:"bytes,10,opt,name=stripeEmail,proto3" json:"stripeEmail,omitempty"` - StripeToken string `protobuf:"bytes,11,opt,name=stripeToken,proto3" json:"stripeToken,omitempty"` - Token string `protobuf:"bytes,12,opt,name=token,proto3" json:"token,omitempty"` - ResellerCode string `protobuf:"bytes,13,opt,name=resellerCode,proto3" json:"resellerCode,omitempty"` -} - -func (x *PurchaseRequest) Reset() { - *x = PurchaseRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_pro_client_api_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PurchaseRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PurchaseRequest) ProtoMessage() {} - -func (x *PurchaseRequest) ProtoReflect() protoreflect.Message { - mi := &file_pro_client_api_proto_msgTypes[7] - 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 PurchaseRequest.ProtoReflect.Descriptor instead. -func (*PurchaseRequest) Descriptor() ([]byte, []int) { - return file_pro_client_api_proto_rawDescGZIP(), []int{7} -} - -func (x *PurchaseRequest) GetProvider() Provider { - if x != nil { - return x.Provider - } - return Provider_PROVIDER_UNSET -} - -func (x *PurchaseRequest) GetEmail() string { - if x != nil { - return x.Email - } - return "" -} - -func (x *PurchaseRequest) GetPlan() string { - if x != nil { - return x.Plan - } - return "" -} - -func (x *PurchaseRequest) GetCardNumber() string { - if x != nil { - return x.CardNumber - } - return "" -} - -func (x *PurchaseRequest) GetExpDate() string { - if x != nil { - return x.ExpDate - } - return "" -} - -func (x *PurchaseRequest) GetCvc() string { - if x != nil { - return x.Cvc - } - return "" -} - -func (x *PurchaseRequest) GetCurrency() string { - if x != nil { - return x.Currency - } - return "" -} - -func (x *PurchaseRequest) GetDeviceName() string { - if x != nil { - return x.DeviceName - } - return "" -} - -func (x *PurchaseRequest) GetStripePublicKey() string { - if x != nil { - return x.StripePublicKey - } - return "" -} - -func (x *PurchaseRequest) GetStripeEmail() string { - if x != nil { - return x.StripeEmail - } - return "" -} - -func (x *PurchaseRequest) GetStripeToken() string { - if x != nil { - return x.StripeToken - } - return "" -} - -func (x *PurchaseRequest) GetToken() string { - if x != nil { - return x.Token - } - return "" -} - -func (x *PurchaseRequest) GetResellerCode() string { - if x != nil { - return x.ResellerCode - } - return "" -} - -type PurchaseResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` -} - -func (x *PurchaseResponse) Reset() { - *x = PurchaseResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_pro_client_api_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PurchaseResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PurchaseResponse) ProtoMessage() {} - -func (x *PurchaseResponse) ProtoReflect() protoreflect.Message { - mi := &file_pro_client_api_proto_msgTypes[8] - 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 PurchaseResponse.ProtoReflect.Descriptor instead. -func (*PurchaseResponse) Descriptor() ([]byte, []int) { - return file_pro_client_api_proto_rawDescGZIP(), []int{8} -} - -func (x *PurchaseResponse) GetSuccess() bool { - if x != nil { - return x.Success - } - return false -} - -var File_pro_client_api_proto protoreflect.FileDescriptor - -var file_pro_client_api_proto_rawDesc = []byte{ - 0x0a, 0x14, 0x70, 0x72, 0x6f, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x61, 0x70, 0x69, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xbf, 0x04, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x50, 0x6c, 0x61, 0x6e, - 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, - 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x65, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x62, 0x65, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x64, 0x50, 0x72, 0x69, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x08, 0x75, 0x73, 0x64, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x29, 0x0a, 0x05, - 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x50, 0x72, - 0x6f, 0x50, 0x6c, 0x61, 0x6e, 0x2e, 0x50, 0x72, 0x69, 0x63, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x52, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x12, 0x56, 0x0a, 0x14, 0x65, 0x78, 0x70, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x6e, 0x74, 0x68, 0x6c, 0x79, 0x50, 0x72, 0x69, 0x63, 0x65, 0x18, - 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x50, 0x72, 0x6f, 0x50, 0x6c, 0x61, 0x6e, 0x2e, - 0x45, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x6e, 0x74, 0x68, 0x6c, 0x79, 0x50, - 0x72, 0x69, 0x63, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x65, 0x78, 0x70, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x6e, 0x74, 0x68, 0x6c, 0x79, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, - 0x36, 0x0a, 0x16, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x73, 0x74, 0x42, 0x69, 0x6c, 0x6c, - 0x65, 0x64, 0x4f, 0x6e, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x16, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x73, 0x74, 0x42, 0x69, 0x6c, 0x6c, 0x65, 0x64, - 0x4f, 0x6e, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x6f, 0x6e, 0x65, 0x4d, 0x6f, - 0x6e, 0x74, 0x68, 0x43, 0x6f, 0x73, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6f, - 0x6e, 0x65, 0x4d, 0x6f, 0x6e, 0x74, 0x68, 0x43, 0x6f, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, - 0x6f, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x66, 0x6f, 0x72, - 0x6d, 0x61, 0x74, 0x74, 0x65, 0x64, 0x42, 0x6f, 0x6e, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x64, 0x42, 0x6f, 0x6e, 0x75, - 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x72, 0x65, 0x6e, 0x65, 0x77, 0x61, 0x6c, 0x54, 0x65, 0x78, 0x74, - 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x65, 0x6e, 0x65, 0x77, 0x61, 0x6c, 0x54, - 0x65, 0x78, 0x74, 0x1a, 0x38, 0x0a, 0x0a, 0x50, 0x72, 0x69, 0x63, 0x65, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x47, 0x0a, - 0x19, 0x45, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x6e, 0x74, 0x68, 0x6c, 0x79, - 0x50, 0x72, 0x69, 0x63, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x2f, 0x0a, 0x0d, 0x50, 0x6c, 0x61, 0x6e, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x05, 0x70, 0x6c, 0x61, 0x6e, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x50, 0x72, 0x6f, 0x50, 0x6c, 0x61, 0x6e, - 0x52, 0x05, 0x70, 0x6c, 0x61, 0x6e, 0x73, 0x22, 0x94, 0x01, 0x0a, 0x12, 0x50, 0x72, 0x6f, 0x50, - 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x12, - 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x12, 0x31, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x1d, 0x2e, 0x50, 0x72, 0x6f, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, - 0x76, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x04, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x37, 0x0a, 0x09, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x5d, - 0x0a, 0x10, 0x50, 0x72, 0x6f, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x68, - 0x6f, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x31, 0x0a, 0x09, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, - 0x50, 0x72, 0x6f, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, - 0x65, 0x72, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x22, 0xb8, 0x01, - 0x0a, 0x16, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x09, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x50, 0x61, - 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x1a, 0x58, - 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xbc, 0x01, 0x0a, 0x16, 0x50, 0x61, 0x79, - 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x64, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, - 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, - 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, - 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, - 0x43, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x22, 0x35, 0x0a, 0x17, 0x50, 0x61, 0x79, 0x6d, 0x65, - 0x6e, 0x74, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x22, 0x92, - 0x03, 0x0a, 0x0f, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x25, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x09, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, - 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, - 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, - 0x12, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, - 0x6c, 0x61, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x61, 0x72, 0x64, 0x4e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x61, 0x72, 0x64, 0x4e, 0x75, 0x6d, - 0x62, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x78, 0x70, 0x44, 0x61, 0x74, 0x65, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x65, 0x78, 0x70, 0x44, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, - 0x03, 0x63, 0x76, 0x63, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, 0x76, 0x63, 0x12, - 0x1a, 0x0a, 0x08, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x64, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x73, - 0x74, 0x72, 0x69, 0x70, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x09, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x74, 0x72, 0x69, 0x70, 0x65, 0x50, 0x75, 0x62, 0x6c, - 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x74, 0x72, 0x69, 0x70, 0x65, 0x45, - 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x74, 0x72, 0x69, - 0x70, 0x65, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x74, 0x72, 0x69, 0x70, - 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x74, - 0x72, 0x69, 0x70, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, - 0x65, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, - 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x73, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x18, - 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x43, - 0x6f, 0x64, 0x65, 0x22, 0x2c, 0x0a, 0x10, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 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, 0x2a, 0x39, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, - 0x0e, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x44, 0x45, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x45, 0x54, 0x10, - 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x50, 0x45, 0x10, 0x01, 0x12, 0x0d, 0x0a, - 0x09, 0x46, 0x52, 0x45, 0x45, 0x4b, 0x41, 0x53, 0x53, 0x41, 0x10, 0x02, 0x42, 0x2d, 0x5a, 0x2b, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x65, 0x74, 0x6c, 0x61, - 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x2f, 0x66, 0x6c, 0x61, 0x73, 0x68, 0x6c, 0x69, 0x67, 0x68, 0x74, - 0x2f, 0x70, 0x72, 0x6f, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, -} - -var ( - file_pro_client_api_proto_rawDescOnce sync.Once - file_pro_client_api_proto_rawDescData = file_pro_client_api_proto_rawDesc -) - -func file_pro_client_api_proto_rawDescGZIP() []byte { - file_pro_client_api_proto_rawDescOnce.Do(func() { - file_pro_client_api_proto_rawDescData = protoimpl.X.CompressGZIP(file_pro_client_api_proto_rawDescData) - }) - return file_pro_client_api_proto_rawDescData -} - -var file_pro_client_api_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_pro_client_api_proto_msgTypes = make([]protoimpl.MessageInfo, 13) -var file_pro_client_api_proto_goTypes = []interface{}{ - (Provider)(0), // 0: Provider - (*ProPlan)(nil), // 1: ProPlan - (*PlansResponse)(nil), // 2: PlansResponse - (*ProPaymentProvider)(nil), // 3: ProPaymentProvider - (*ProPaymentMethod)(nil), // 4: ProPaymentMethod - (*PaymentMethodsResponse)(nil), // 5: PaymentMethodsResponse - (*PaymentRedirectRequest)(nil), // 6: PaymentRedirectRequest - (*PaymentRedirectResponse)(nil), // 7: PaymentRedirectResponse - (*PurchaseRequest)(nil), // 8: PurchaseRequest - (*PurchaseResponse)(nil), // 9: PurchaseResponse - nil, // 10: ProPlan.PriceEntry - nil, // 11: ProPlan.ExpectedMonthlyPriceEntry - nil, // 12: ProPaymentProvider.DataEntry - nil, // 13: PaymentMethodsResponse.ProvidersEntry - (*structpb.ListValue)(nil), // 14: google.protobuf.ListValue -} -var file_pro_client_api_proto_depIdxs = []int32{ - 10, // 0: ProPlan.price:type_name -> ProPlan.PriceEntry - 11, // 1: ProPlan.expectedMonthlyPrice:type_name -> ProPlan.ExpectedMonthlyPriceEntry - 1, // 2: PlansResponse.plans:type_name -> ProPlan - 12, // 3: ProPaymentProvider.data:type_name -> ProPaymentProvider.DataEntry - 3, // 4: ProPaymentMethod.providers:type_name -> ProPaymentProvider - 13, // 5: PaymentMethodsResponse.providers:type_name -> PaymentMethodsResponse.ProvidersEntry - 0, // 6: PurchaseRequest.provider:type_name -> Provider - 14, // 7: PaymentMethodsResponse.ProvidersEntry.value:type_name -> google.protobuf.ListValue - 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_pro_client_api_proto_init() } -func file_pro_client_api_proto_init() { - if File_pro_client_api_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_pro_client_api_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ProPlan); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pro_client_api_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PlansResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pro_client_api_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ProPaymentProvider); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pro_client_api_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ProPaymentMethod); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pro_client_api_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PaymentMethodsResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pro_client_api_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PaymentRedirectRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pro_client_api_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PaymentRedirectResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pro_client_api_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PurchaseRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_pro_client_api_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PurchaseResponse); 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_pro_client_api_proto_rawDesc, - NumEnums: 1, - NumMessages: 13, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_pro_client_api_proto_goTypes, - DependencyIndexes: file_pro_client_api_proto_depIdxs, - EnumInfos: file_pro_client_api_proto_enumTypes, - MessageInfos: file_pro_client_api_proto_msgTypes, - }.Build() - File_pro_client_api_proto = out.File - file_pro_client_api_proto_rawDesc = nil - file_pro_client_api_proto_goTypes = nil - file_pro_client_api_proto_depIdxs = nil -} diff --git a/pro/client/api.proto b/pro/client/api.proto deleted file mode 100644 index d4eb2d6c7..000000000 --- a/pro/client/api.proto +++ /dev/null @@ -1,74 +0,0 @@ -syntax = "proto3"; -import "google/protobuf/struct.proto"; -option go_package = "github.com/getlantern/flashlight/pro/client"; - -message ProPlan { - string id = 1; - string description = 2; - bool bestValue = 3; - int64 usdPrice = 4; - map price = 5; - map expectedMonthlyPrice = 6; - string totalCostBilledOneTime = 7; - string oneMonthCost = 8; - string totalCost = 9; - string formattedBonus = 10; - string renewalText = 11; -} - -message PlansResponse { - repeated ProPlan plans = 1; -} - -message ProPaymentProvider { - string name = 1; - map data = 2; -} - -message ProPaymentMethod { - string method = 1; - repeated ProPaymentProvider providers = 2; -} - -message PaymentMethodsResponse { - map providers = 1; -} - -enum Provider { - PROVIDER_UNSET = 0; - STRIPE = 1; - FREEKASSA = 2; -} - -message PaymentRedirectRequest { - string plan = 1; - string provider = 2; - string currency = 3; - string email = 4; - string deviceName = 5; - string countryCode = 6; -} - -message PaymentRedirectResponse { - string redirect = 1; -} - -message PurchaseRequest { - Provider provider = 1; - string email = 2; - string plan = 3; - string cardNumber = 4; - string expDate = 5; - string cvc = 6; - string currency = 7; - string deviceName = 8; - string stripePublicKey = 9; - string stripeEmail = 10; - string stripeToken = 11; - string token = 12; - string resellerCode = 13; -} - -message PurchaseResponse { - bool success = 1; -} diff --git a/pro/client/client.go b/pro/client/client.go index 75374e099..913044e64 100644 --- a/pro/client/client.go +++ b/pro/client/client.go @@ -134,52 +134,6 @@ func (c *Client) Plans(user common.UserConfig) (*plansResponse, error) { return resp, nil } -type paymentRedirectResponse struct { - BaseResponse - *PaymentRedirectResponse `json:",inline"` -} - -// PaymentRedirect is called when the continue to payment button is clicked and returns a redirect URL -func (c *Client) PaymentRedirect(user common.UserConfig, req *PaymentRedirectRequest) (*paymentRedirectResponse, error) { - query := url.Values{ - "countryCode": {req.CountryCode}, - "deviceName": {req.DeviceName}, - "email": {req.Email}, - "plan": {req.Plan}, - "provider": {req.Provider}, - } - - b, _ := json.Marshal(user) - log.Debugf("User config is %v", string(b)) - - resp := &paymentRedirectResponse{PaymentRedirectResponse: &PaymentRedirectResponse{}} - if err := c.execute(user, http.MethodGet, "payment-redirect", query, resp); err != nil { - log.Errorf("Failed to fetch payment redirect: %v", err) - return nil, err - } - log.Debugf("Redirect is %s", resp.Redirect) - return resp, nil -} - -type paymentMethodsResponse struct { - *PaymentMethodsResponse `json:",inline"` - BaseResponse -} - -// PaymentMethods returns a list of payment options available to the given user -func (c *Client) PaymentMethods(user common.UserConfig) (*paymentMethodsResponse, error) { - query := url.Values{ - "locale": {user.GetLanguage()}, - } - - resp := &paymentMethodsResponse{PaymentMethodsResponse: &PaymentMethodsResponse{}} - if err := c.execute(user, http.MethodGet, "plans-v3", query, resp); err != nil { - log.Errorf("Failed to fetch payment methods: %v", err) - return nil, err - } - return resp, nil -} - // RecoverProAccount attempts to recover an existing Pro account linked to this email address and device ID func (c *Client) RecoverProAccount(user common.UserConfig, emailAddress string) (*LinkResponse, error) { query := url.Values{ From 5a3b313753c1689257b38d692b44dd7bfb876496 Mon Sep 17 00:00:00 2001 From: atavism Date: Wed, 20 Mar 2024 13:05:56 -0700 Subject: [PATCH 02/10] remove Plans call --- pro/client/client.go | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/pro/client/client.go b/pro/client/client.go index 913044e64..5c33d1aa3 100644 --- a/pro/client/client.go +++ b/pro/client/client.go @@ -114,26 +114,6 @@ func (c *Client) UserData(user common.UserConfig) (*UserDataResponse, error) { return resp, nil } -type plansResponse struct { - BaseResponse - *PlansResponse `json:",inline"` -} - -// Plans returns a list of Pro plans -func (c *Client) Plans(user common.UserConfig) (*plansResponse, error) { - query := url.Values{ - "locale": {user.GetLanguage()}, - } - - resp := &plansResponse{PlansResponse: &PlansResponse{}} - if err := c.execute(user, http.MethodGet, "plans", query, resp); err != nil { - log.Errorf("Failed to fetch plans: %v", err) - return nil, err - } - - return resp, nil -} - // RecoverProAccount attempts to recover an existing Pro account linked to this email address and device ID func (c *Client) RecoverProAccount(user common.UserConfig, emailAddress string) (*LinkResponse, error) { query := url.Values{ From fda54a6bdbcbced2417a764bafba9db21c179a17 Mon Sep 17 00:00:00 2001 From: atavism Date: Mon, 1 Apr 2024 04:54:16 -0700 Subject: [PATCH 03/10] remove pro client --- pro/client/client.go | 324 -------------------------------------- pro/client/client_test.go | 139 ---------------- pro/client/user.go | 26 --- pro/http.go | 29 ---- pro/http_test.go | 42 ----- pro/migrate.go | 18 --- pro/proxy.go | 156 ------------------ pro/proxy_test.go | 103 ------------ pro/user_data.go | 162 ------------------- pro/user_data_test.go | 57 ------- 10 files changed, 1056 deletions(-) delete mode 100644 pro/client/client.go delete mode 100644 pro/client/client_test.go delete mode 100644 pro/client/user.go delete mode 100644 pro/http.go delete mode 100644 pro/http_test.go delete mode 100644 pro/migrate.go delete mode 100644 pro/proxy.go delete mode 100644 pro/proxy_test.go delete mode 100644 pro/user_data.go delete mode 100644 pro/user_data_test.go diff --git a/pro/client/client.go b/pro/client/client.go deleted file mode 100644 index 5c33d1aa3..000000000 --- a/pro/client/client.go +++ /dev/null @@ -1,324 +0,0 @@ -package client - -import ( - "bytes" - "encoding/json" - "errors" - "io/ioutil" - "math" - "net/http" - "net/url" - "strconv" - "strings" - "time" - - "github.com/getlantern/flashlight/v7/common" - "github.com/getlantern/golog" -) - -var ( - log = golog.LoggerFor("pro-server-client") - - defaultTimeout = time.Second * 30 - maxRetries = 4 - retryBaseTime = time.Millisecond * 100 -) - -var ( - ErrAPIUnavailable = errors.New("API unavailable.") -) - -type baseResponse interface { - status() string - error() string -} - -type BaseResponse struct { - Status string `json:"status"` - Error string `json:"error"` - ErrorId string `json:"errorId"` -} - -func (resp BaseResponse) status() string { - return resp.Status -} - -func (resp BaseResponse) error() string { - return resp.Error -} - -type UserDataResponse struct { - BaseResponse - User `json:",inline"` -} - -type LinkResponse struct { - BaseResponse - UserID int `json:"userID"` - ProToken string `json:"token"` -} - -type LinkCodeResponse struct { - BaseResponse - Code string - ExpireAt int64 -} - -type Client struct { - httpClient *http.Client - preparePro func(*http.Request, common.UserConfig) -} - -// NewClient creates a new pro client. -func NewClient(httpClient *http.Client, preparePro func(r *http.Request, uc common.UserConfig)) *Client { - if httpClient == nil { - httpClient = &http.Client{ - Timeout: defaultTimeout, - } - } - return &Client{httpClient: httpClient, preparePro: preparePro} -} - -// UserCreate creates an user without asking for any payment. -func (c *Client) UserCreate(user common.UserConfig) (res *UserDataResponse, err error) { - body := strings.NewReader(url.Values{"locale": {user.GetLanguage()}}.Encode()) - req, err := http.NewRequest(http.MethodPost, "https://"+common.ProAPIHost+"/user-create", body) - if err != nil { - return nil, err - } - - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - - payload, err := c.do(user, req) - if err != nil { - return nil, err - } - err = json.Unmarshal(payload, &res) - return -} - -// UserData Returns all user data, including payments, referrals and all -// available fields. -func (c *Client) UserData(user common.UserConfig) (*UserDataResponse, error) { - query := url.Values{ - "timeout": {"10"}, - "locale": {user.GetLanguage()}, - } - - resp := &UserDataResponse{} - if err := c.execute(user, http.MethodGet, "user-data", query, resp); err != nil { - log.Errorf("Failed to get user data: %v", err) - return nil, err - } - - return resp, nil -} - -// RecoverProAccount attempts to recover an existing Pro account linked to this email address and device ID -func (c *Client) RecoverProAccount(user common.UserConfig, emailAddress string) (*LinkResponse, error) { - query := url.Values{ - "email": {emailAddress}, - "locale": {user.GetLanguage()}, - } - - resp := &LinkResponse{} - if err := c.execute(user, http.MethodPost, "user-recover", query, resp); err != nil { - log.Errorf("Failed to recover pro user: %v", err) - return nil, err - } - - return resp, nil -} - -// EmailExists checks whether a Pro account exists with the given email address -func (c *Client) EmailExists(user common.UserConfig, emailAddress string) error { - query := url.Values{ - "email": {emailAddress}, - } - - resp := &BaseResponse{} - if err := c.execute(user, http.MethodGet, "email-exists", query, resp); err != nil { - log.Errorf("Failed to check if email exists: %v", err) - return err - } - - return nil -} - -// RequestRecoveryEmail requests an account recovery email for linking to an existing pro account -func (c *Client) RequestRecoveryEmail(user common.UserConfig, deviceName, emailAddress string) (err error) { - query := url.Values{ - "email": {emailAddress}, - "deviceName": {deviceName}, - "locale": {user.GetLanguage()}, - } - - resp := &BaseResponse{} - if err := c.execute(user, http.MethodPost, "user-link-request", query, resp); err != nil { - log.Errorf("Failed to request a recovery code: %v", err) - return err - } - - return nil -} - -// ValidateRecoveryCode validates the given recovery code and finishes linking the device, returning the user_id and pro_token for the account. -func (c *Client) ValidateRecoveryCode(user common.UserConfig, code string) (*LinkResponse, error) { - query := url.Values{ - "code": {code}, - "locale": {user.GetLanguage()}, - } - - resp := &LinkResponse{} - if err := c.execute(user, http.MethodPost, "user-link-validate", query, resp); err != nil { - log.Errorf("Failed to validate recovery code: %v", err) - return nil, err - } - - return resp, nil -} - -// RequestDeviceLinkingCode requests a new device linking code to allow linking the current device to a pro account via an existing pro device. -func (c *Client) RequestDeviceLinkingCode(user common.UserConfig, deviceName string) (*LinkCodeResponse, error) { - query := url.Values{ - "deviceName": {deviceName}, - "locale": {user.GetLanguage()}, - } - - resp := &LinkCodeResponse{} - if err := c.execute(user, http.MethodPost, "link-code-request", query, resp); err != nil { - log.Errorf("Failed to get link code: %v", err) - return nil, err - } - - return resp, nil -} - -// ValidateDeviceLinkingCode validates a device linking code to allow linking the current device to a pro account via an existing pro device. -func (c *Client) ValidateDeviceLinkingCode(user common.UserConfig, deviceName, code string) (*LinkResponse, error) { - query := url.Values{ - "code": {code}, - "deviceName": {deviceName}, - "locale": {user.GetLanguage()}, - } - - resp := &LinkResponse{} - if err := c.execute(user, http.MethodPost, "link-code-redeem", query, resp); err != nil { - log.Errorf("Failed to validate link code: %v", err) - return nil, err - } - - return resp, nil -} - -// MigrateDeviceID migrates from the old device ID scheme to the new -func (c *Client) MigrateDeviceID(user common.UserConfig, oldDeviceID string) error { - query := url.Values{ - "oldDeviceID": {oldDeviceID}, - } - - resp := &BaseResponse{} - return c.execute(user, http.MethodPost, "migrate-device-id", query, resp) -} - -// RedeemResellerCode redeems a reseller code for the given user -// -// Note: In reality, the response for this route from pro-server is not -// BaseResponse but of this type -// https://github.com/getlantern/pro-server-neu/blob/34bcdc042e983bf9504014aa066bba6bdedcebdb/handlers/purchase.go#L201. -// That being said, we don't really care about the response from pro-server -// here. We just wanna know if it succeeded or failed, which is encapsulated in the fields of BaseResponse. -func (c *Client) RedeemResellerCode(user common.UserConfig, emailAddress, resellerCode, deviceName, currency string) (*BaseResponse, error) { - query := url.Values{ - "email": {emailAddress}, - "resellerCode": {resellerCode}, - "idempotencyKey": {strconv.FormatInt(time.Now().UnixMilli(), 10)}, - "currency": {currency}, - "deviceName": {deviceName}, - "provider": {"reseller-code"}, - } - - resp := &BaseResponse{} - if err := c.execute(user, http.MethodPost, "purchase", query, resp); err != nil { - log.Errorf("Failed to redeem reseller code: %v", err) - return nil, err - } - - return resp, nil -} - -func (c *Client) do(user common.UserConfig, req *http.Request) ([]byte, error) { - var buf []byte - if req.Body != nil { - var err error - buf, err = ioutil.ReadAll(req.Body) - if err != nil { - return nil, err - } - } - - c.preparePro(req, user) - - for i := 0; i < maxRetries; i++ { - client := c.httpClient - log.Debugf("%s %s", req.Method, req.URL) - if len(buf) > 0 { - req.Body = ioutil.NopCloser(bytes.NewBuffer(buf)) - } - - res, err := client.Do(req) - if err == nil { - defer res.Body.Close() - switch res.StatusCode { - case 200: - body, err := ioutil.ReadAll(res.Body) - return body, err - case 202: - log.Debugf("Received 202, retrying idempotent operation immediately.") - continue - default: - body, err := ioutil.ReadAll(res.Body) - if err == nil { - log.Debugf("Expecting 200, got: %d, body: %v", res.StatusCode, string(body)) - } else { - log.Debugf("Expecting 200, got: %d, could not get body: %v", res.StatusCode, err) - } - } - } else { - log.Debugf("Do: %v, res: %v", err, res) - } - - retryTime := time.Duration(math.Pow(2, float64(i))) * retryBaseTime - log.Debugf("failed, waiting %v to retry.", retryTime) - time.Sleep(retryTime) - } - return nil, ErrAPIUnavailable -} - -func (c *Client) execute(user common.UserConfig, method, path string, query url.Values, resp baseResponse) error { - req, err := http.NewRequest(method, "https://"+common.ProAPIHost+"/"+path, nil) - if err != nil { - return err - } - - req.Header.Set("Referer", "http://localhost:37457/") - - query["locale"] = []string{user.GetLanguage()} - req.URL.RawQuery = query.Encode() - - payload, err := c.do(user, req) - if err != nil { - return err - } - - err = json.Unmarshal(payload, &resp) - if err != nil { - return err - } - - if resp.status() == "error" { - return errors.New(resp.error()) - } - - return nil -} diff --git a/pro/client/client_test.go b/pro/client/client_test.go deleted file mode 100644 index 0ac321cc1..000000000 --- a/pro/client/client_test.go +++ /dev/null @@ -1,139 +0,0 @@ -package client - -import ( - "fmt" - "net/http" - "testing" - "time" - - "github.com/pborman/uuid" - "github.com/stretchr/testify/assert" - - "github.com/getlantern/flashlight/v7/common" -) - -func generateDeviceId() string { - return uuid.New() -} - -func generateUser() *common.UserConfigData { - return common.NewUserConfigData(common.DefaultAppName, generateDeviceId(), 35, "aasfge", nil, "en-US") -} - -func init() { - common.ForceStaging() -} - -func createClient() *Client { - return NewClient(nil, func(req *http.Request, uc common.UserConfig) { - common.AddCommonHeaders(uc, req) - }) -} - -func TestCreateUser(t *testing.T) { - user := generateUser() - - res, err := createClient().UserCreate(user) - if !assert.NoError(t, err) { - return - } - - assert.True(t, res.User.ID != 0) - assert.True(t, res.User.Expiration == 0) - assert.True(t, res.User.Token != "") - assert.True(t, res.User.Code != "") - assert.True(t, res.User.Referral == res.User.Code) -} - -func TestGetUserData(t *testing.T) { - user := generateUser() - res, err := createClient().UserCreate(user) - if !assert.NoError(t, err) { - return - } - user.UserID = res.User.ID - user.Token = res.User.Token - - // fetch this user's info with a new client - res, err = createClient().UserData(user) - if assert.NoError(t, err) { - assert.True(t, res.User.ID != 0) - assert.Equal(t, res.User.ID, user.UserID) - } -} - -func TestGetPlans(t *testing.T) { - user := generateUser() - res, err := createClient().UserCreate(user) - if !assert.NoError(t, err) { - return - } - user.UserID = res.User.ID - user.Token = res.User.Token - - plansRes, err := createClient().Plans(user) - if !assert.NoError(t, err) { - return - } - fmt.Println(plansRes.PlansResponse.Plans) - assert.True(t, len(plansRes.PlansResponse.Plans) > 0) -} - -func TestUserDataMissing(t *testing.T) { - user := generateUser() - - _, err := createClient().UserData(user) - assert.Error(t, err) -} - -func TestUserDataWrong(t *testing.T) { - user := generateUser() - user.UserID = -1 - user.Token = "nonsense" - - _, err := createClient().UserData(user) - if assert.Error(t, err) { - assert.Contains(t, err.Error(), "Not authorized") - } -} - -func TestRequestDeviceLinkingCode(t *testing.T) { - user := generateUser() - res, err := createClient().UserCreate(user) - if !assert.NoError(t, err) { - return - } - user.UserID = res.User.ID - user.Token = res.User.Token - - lcr, err := createClient().RequestDeviceLinkingCode(user, "Test Device") - if assert.NoError(t, err) { - assert.NotEmpty(t, lcr.Code) - assert.True(t, time.Unix(lcr.ExpireAt, 0).After(time.Now())) - } -} - -func TestCreateUniqueUsers(t *testing.T) { - userA := generateUser() - res, err := createClient().UserCreate(userA) - if !assert.NoError(t, err) { - return - } - assert.True(t, res.User.ID != 0) - assert.True(t, res.User.Token != "") - userA.UserID = res.User.ID - userA.Token = res.User.Token - - userB := generateUser() - res, err = createClient().UserCreate(userB) - if !assert.NoError(t, err) { - return - } - assert.True(t, res.User.ID != 0) - assert.True(t, res.User.Token != "") - userB.UserID = res.User.ID - userB.Token = res.User.Token - - assert.NotEqual(t, userA.UserID, userB.UserID) - assert.NotEqual(t, userA.Token, userB.Token) -} diff --git a/pro/client/user.go b/pro/client/user.go deleted file mode 100644 index 6b101e2f1..000000000 --- a/pro/client/user.go +++ /dev/null @@ -1,26 +0,0 @@ -package client - -type Device struct { - Id string `json:"id"` - Name string `json:"name"` - Created int64 `json:"created"` -} - -type Auth struct { - ID int64 `json:"userId"` - Token string `json:"token"` -} - -type User struct { - Auth `json:",inline"` - Email string `json:"email"` - PhoneNumber string `json:"telephone"` - UserStatus string `json:"userStatus"` - Locale string `json:"locale"` - Expiration int64 `json:"expiration"` - Devices []Device `json:"devices"` - Code string `json:"code"` - ExpireAt int64 `json:"expireAt"` - Referral string `json:"referral"` - YinbiEnabled bool `json:"yinbiEnabled"` -} diff --git a/pro/http.go b/pro/http.go deleted file mode 100644 index ce765cd5b..000000000 --- a/pro/http.go +++ /dev/null @@ -1,29 +0,0 @@ -package pro - -import ( - "net/http" - "time" - - "github.com/getlantern/flashlight/v7/proxied" -) - -var ( - httpClient = getHTTPClient(proxied.ParallelForIdempotent()) -) - -// GetHTTPClient creates a new http.Client that uses domain fronting and direct -// proxies. -func GetHTTPClient() *http.Client { - return httpClient -} - -func getHTTPClient(rt http.RoundTripper) *http.Client { - return &http.Client{ - Transport: rt, - // Don't follow redirects - CheckRedirect: func(req *http.Request, via []*http.Request) error { - return http.ErrUseLastResponse - }, - Timeout: 30 * time.Second, - } -} diff --git a/pro/http_test.go b/pro/http_test.go deleted file mode 100644 index 114a2040e..000000000 --- a/pro/http_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package pro - -import ( - "io/ioutil" - "net/http" - "testing" - - "github.com/getlantern/golog" - "github.com/stretchr/testify/assert" -) - -func TestClient(t *testing.T) { - log := golog.LoggerFor("pro-http-test") - url := "https://api.getiantem.org/plans" - req, err := http.NewRequest("GET", url, nil) - if err != nil { - assert.Fail(t, "Could not get request") - } - - // Just use the default transport since otherwise test setup is difficult. - // This means it does not actually touch the proxying code, but that should - // be tested separately. - client := getHTTPClient(http.DefaultTransport) - res, e := client.Do(req) - - if !assert.NoError(t, e) { - return - } - log.Debugf("Got responsde code: %v", res.StatusCode) - assert.NotNil(t, res.Body, "nil plans response body?") - - body, bodyErr := ioutil.ReadAll(res.Body) - assert.Nil(t, bodyErr) - assert.True(t, len(body) > 0, "Should have received some body") - - res, e = client.Do(req) - assert.Nil(t, e) - - body, bodyErr = ioutil.ReadAll(res.Body) - assert.Nil(t, bodyErr) - assert.True(t, len(body) > 0, "Should have received some body") -} diff --git a/pro/migrate.go b/pro/migrate.go deleted file mode 100644 index 2777ffca0..000000000 --- a/pro/migrate.go +++ /dev/null @@ -1,18 +0,0 @@ -package pro - -import ( - "net/http" - - "github.com/getlantern/flashlight/v7/common" - "github.com/getlantern/flashlight/v7/pro/client" -) - -// MigrateDeviceID migrates the user's device ID from the old to the new scheme (only relevant to desktop builds) -func MigrateDeviceID(uc common.UserConfig, oldDeviceID string) error { - return migrateDeviceIDWithClient(uc, oldDeviceID, httpClient) -} - -func migrateDeviceIDWithClient(uc common.UserConfig, oldDeviceID string, hc *http.Client) error { - logger.Debugf("Migrating deviceID from %v to %v", oldDeviceID, uc.GetDeviceID()) - return client.NewClient(hc, PrepareProRequestWithOptions).MigrateDeviceID(uc, oldDeviceID) -} diff --git a/pro/proxy.go b/pro/proxy.go deleted file mode 100644 index 17f337696..000000000 --- a/pro/proxy.go +++ /dev/null @@ -1,156 +0,0 @@ -package pro - -import ( - "bytes" - "compress/gzip" - "encoding/json" - "io" - "io/ioutil" - "net/http" - "net/http/httputil" - "strconv" - "strings" - - "github.com/getlantern/flashlight/v7/common" - "github.com/getlantern/flashlight/v7/pro/client" - "github.com/getlantern/golog" -) - -var ( - log = golog.LoggerFor("flashlight.pro") -) - -type proxyTransport struct { - // Satisfies http.RoundTripper -} - -func (pt *proxyTransport) processOptions(req *http.Request) *http.Response { - resp := &http.Response{ - StatusCode: http.StatusOK, - Header: http.Header{ - "Connection": {"keep-alive"}, - "Via": {"Lantern Client"}, - }, - Body: ioutil.NopCloser(strings.NewReader("preflight complete")), - } - if !common.ProcessCORS(resp.Header, req) { - return &http.Response{ - StatusCode: http.StatusForbidden, - } - } - return resp -} - -func (pt *proxyTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) { - if req.Method == "OPTIONS" { - // No need to proxy the OPTIONS request. - return pt.processOptions(req), nil - } - origin := req.Header.Get("Origin") - // Workaround for https://github.com/getlantern/pro-server/issues/192 - req.Header.Del("Origin") - resp, err = GetHTTPClient().Do(req) - if err != nil { - log.Errorf("Could not issue HTTP request? %v", err) - return - } - - // Put the header back for subsequent CORS processing. - req.Header.Set("Origin", origin) - common.ProcessCORS(resp.Header, req) - if req.URL.Path != "/user-data" || resp.StatusCode != http.StatusOK { - return - } - // Try to update user data implicitly - _userID := req.Header.Get("X-Lantern-User-Id") - if _userID == "" { - log.Error("Request has an empty user ID") - return - } - userID, parseErr := strconv.ParseInt(_userID, 10, 64) - if parseErr != nil { - log.Errorf("User ID %s is invalid", _userID) - return - } - body, readErr := ioutil.ReadAll(resp.Body) - if readErr != nil { - log.Errorf("Error read response body: %v", readErr) - return - } - resp.Body = ioutil.NopCloser(bytes.NewReader(body)) - encoding := resp.Header.Get("Content-Encoding") - var br io.Reader = bytes.NewReader(body) - switch encoding { - case "gzip": - gzr, readErr := gzip.NewReader(bytes.NewReader(body)) - if readErr != nil { - log.Errorf("Unable to decode gzipped data: %v", readErr) - return - } - br = gzr - case "": - default: - log.Errorf("Unsupported response encoding %s", encoding) - return - } - user := client.User{} - readErr = json.NewDecoder(br).Decode(&user) - if readErr != nil { - log.Errorf("Error decoding JSON: %v", readErr) - return - } - log.Debugf("Updating user data implicitly for user %v", userID) - setUserData(userID, &user) - return -} - -// PrepareProRequestWithOptions normalizes requests to the pro server with -// device ID, user ID, etc set. -func PrepareProRequestWithOptions(r *http.Request, uc common.UserConfig) { - prepareProRequest(r, uc, true) -} - -// PrepareProRequest normalizes requests to the pro server without overwriting -// device ID, user ID, etc. -func PrepareProRequest(r *http.Request, uc common.UserConfig) { - prepareProRequest(r, uc, false) -} - -func prepareProRequest(r *http.Request, uc common.UserConfig, options bool) { - r.URL.Scheme = "http" - r.URL.Host = common.ProAPIHost - // XXX <03-02-22, soltzen> Requests coming from lantern-desktop's UI client - // will always carry lantern-desktop's server address (i.e., - // [here](https://github.com/getlantern/lantern-desktop/blob/87370cca9c895d0e0296b4d16e292ad8adbdae33/server/defaults_static.go#L1)) - // in their 'Host' header (like this: 'Host: localhost:16823'). This is - // problamatic for many servers (Replica's as well). So, best to either - // wipe it or assign it as the URL's host - r.Host = r.URL.Host - r.RequestURI = "" // http: Request.RequestURI can't be set in client requests. - r.Header.Set("Access-Control-Allow-Headers", strings.Join([]string{ - common.DeviceIdHeader, - common.ProTokenHeader, - common.UserIdHeader, - }, ", ")) - - // Add auth headers only if not present, to avoid race conditions - // when creating new user or switching user, i.e., linking device - // to a new account. (ovewriteAuth=false) - common.AddCommonHeadersWithOptions(uc, r, options) -} - -// APIHandler returns an HTTP handler that specifically looks for and properly -// handles pro server requests. -func APIHandler(uc common.UserConfig) http.Handler { - log.Debugf("Returning pro API handler hitting host: %v", common.ProAPIHost) - return &httputil.ReverseProxy{ - Transport: &proxyTransport{}, - Director: func(r *http.Request) { - // Strip /pro from path. - if strings.HasPrefix(r.URL.Path, "/pro/") { - r.URL.Path = r.URL.Path[4:] - } - PrepareProRequest(r, uc) - }, - } -} diff --git a/pro/proxy_test.go b/pro/proxy_test.go deleted file mode 100644 index 0b628624d..000000000 --- a/pro/proxy_test.go +++ /dev/null @@ -1,103 +0,0 @@ -package pro - -import ( - "bytes" - "compress/gzip" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "net" - "net/http" - "strings" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/getlantern/flashlight/v7/common" - "github.com/getlantern/flashlight/v7/pro/client" - "github.com/getlantern/flashlight/v7/testutils" -) - -func TestProxy(t *testing.T) { - uc := common.NewUserConfigData(common.DefaultAppName, "device", 0, "token", nil, "en-US") - m := &testutils.MockRoundTripper{Header: http.Header{}, Body: strings.NewReader("GOOD")} - httpClient = &http.Client{Transport: m} - l, err := net.Listen("tcp", "localhost:0") - if !assert.NoError(t, err) { - return - } - - addr := l.Addr() - url := fmt.Sprintf("http://%s/pro/abc", addr) - t.Logf("Test server listening at %s", url) - go http.Serve(l, APIHandler(uc)) - - req, err := http.NewRequest("OPTIONS", url, nil) - if !assert.NoError(t, err) { - return - } - - origin := "http://localhost:48933" - req.Header.Set("Origin", origin) - resp, err := (&http.Client{}).Do(req) - if assert.NoError(t, err, "OPTIONS request should succeed") { - assert.Equal(t, 200, resp.StatusCode, "should respond 200 to OPTIONS") - assert.Equal(t, origin, resp.Header.Get("Access-Control-Allow-Origin"), "should respond with correct header") - _ = resp.Body.Close() - } - assert.Nil(t, m.Req, "should not pass the OPTIONS request to origin server") - - req, err = http.NewRequest("GET", url, nil) - if !assert.NoError(t, err) { - return - } - req.Header.Set("Origin", origin) - resp, err = (&http.Client{}).Do(req) - if assert.NoError(t, err, "GET request should have no error") { - assert.Equal(t, 200, resp.StatusCode, "should respond 200 ok") - assert.Equal(t, origin, resp.Header.Get("Access-Control-Allow-Origin"), "should respond with correct header") - assert.NotEmpty(t, resp.Header.Get("Access-Control-Allow-Methods"), "should respond with correct header") - msg, _ := ioutil.ReadAll(resp.Body) - _ = resp.Body.Close() - assert.Equal(t, "GOOD", string(msg), "should respond expected body") - } - if assert.NotNil(t, m.Req, "should pass through non-OPTIONS requests to origin server") { - t.Log(m.Req) - assert.Equal(t, origin, resp.Header.Get("Access-Control-Allow-Origin"), "should respond with correct header") - assert.NotEmpty(t, resp.Header.Get("Access-Control-Allow-Methods"), "should respond with correct header") - } - - url = fmt.Sprintf("http://%s/pro/user-data", addr) - msg, _ := json.Marshal(&client.User{Email: "a@a.com"}) - m.Body = bytes.NewReader(msg) - req, err = http.NewRequest("GET", url, nil) - if !assert.NoError(t, err) { - return - } - req.Header.Set("X-Lantern-User-Id", "1234") - resp, err = (&http.Client{}).Do(req) - if assert.NoError(t, err, "GET request should have no error") { - assert.Equal(t, 200, resp.StatusCode, "should respond 200 ok") - } - user, found := GetUserDataFast(1234) - if assert.True(t, found) { - assert.Equal(t, "a@a.com", user.Email, "should store user data implicitly if response is plain JSON") - } - - var gzipped bytes.Buffer - gw := gzip.NewWriter(&gzipped) - msg, _ = json.Marshal(&client.User{Email: "b@b.com"}) - io.Copy(gw, bytes.NewReader(msg)) - gw.Close() - m.Body = &gzipped - m.Header.Set("Content-Encoding", "gzip") - resp, err = (&http.Client{}).Do(req) - if assert.NoError(t, err, "GET request should have no error") { - assert.Equal(t, 200, resp.StatusCode, "should respond 200 ok") - } - user, found = GetUserDataFast(1234) - if assert.True(t, found) { - assert.Equal(t, "b@b.com", user.Email, "should store user data implicitly if response is gzipped JSON") - } -} diff --git a/pro/user_data.go b/pro/user_data.go deleted file mode 100644 index 3d907f4e0..000000000 --- a/pro/user_data.go +++ /dev/null @@ -1,162 +0,0 @@ -package pro - -import ( - "net/http" - "sync" - - "github.com/getlantern/eventual" - "github.com/getlantern/flashlight/v7/common" - "github.com/getlantern/flashlight/v7/pro/client" - "github.com/getlantern/golog" -) - -var logger = golog.LoggerFor("flashlight.app.pro") - -type userMap struct { - sync.RWMutex - data map[int64]eventual.Value - onUserData []func(current *client.User, new *client.User) -} - -var userData = userMap{ - data: make(map[int64]eventual.Value), - onUserData: make([]func(current *client.User, new *client.User), 0), -} - -// OnUserData allows registering an event handler to learn when the -// user data has been fetched. -func OnUserData(cb func(current *client.User, new *client.User)) { - userData.Lock() - userData.onUserData = append(userData.onUserData, cb) - userData.Unlock() -} - -// OnProStatusChange allows registering an event handler to learn when the -// user's pro status or "yinbi enabled" status has changed. -func OnProStatusChange(cb func(isPro bool, yinbiEnabled bool)) { - OnUserData(func(current *client.User, new *client.User) { - if current == nil || - isActive(current.UserStatus) != isActive(new.UserStatus) || - current.YinbiEnabled != new.YinbiEnabled { - cb(isActive(new.UserStatus), new.YinbiEnabled) - } - }) -} - -func (m *userMap) save(userID int64, u *client.User) { - m.Lock() - v := m.data[userID] - var current *client.User - if v == nil { - v = eventual.NewValue() - } else { - cur, _ := v.Get(0) - current, _ = cur.(*client.User) - } - v.Set(u) - m.data[userID] = v - onUserData := m.onUserData - m.Unlock() - for _, cb := range onUserData { - cb(current, u) - } -} - -func (m *userMap) get(userID int64) (*client.User, bool) { - m.RLock() - v := m.data[userID] - m.RUnlock() - if v == nil { - return nil, false - } - u, valid := v.Get(0) - if !valid { - return nil, false - } - return u.(*client.User), true -} - -// IsProUser indicates whether or not the user is pro, calling the Pro API if -// necessary to determine the status. -func IsProUser(uc common.UserConfig) (isPro bool, statusKnown bool) { - user, found := GetUserDataFast(uc.GetUserID()) - if !found { - var err error - user, err = fetchUserDataWithClient(uc, httpClient) - if err != nil { - logger.Debugf("Got error fetching pro user: %v", err) - return false, false - } - } - return isActive(user.UserStatus), true -} - -// IsProUserFast indicates whether or not the user is pro and whether or not the -// user's status is know, never calling the Pro API to determine the status. -func IsProUserFast(uc common.UserConfig) (isPro bool, statusKnown bool) { - user, found := GetUserDataFast(uc.GetUserID()) - if !found { - return false, false - } - return isActive(user.UserStatus), found -} - -// isActive determines whether the given status is an active status -func isActive(status string) bool { - return status == "active" -} - -// GetUserDataFast gets the user data for the given userID if found. -func GetUserDataFast(userID int64) (*client.User, bool) { - return userData.get(userID) -} - -// NewUser creates a new user via Pro API, and updates local cache. -func NewUser(uc common.UserConfig) (*client.User, error) { - return newUserWithClient(uc, httpClient) -} - -// NewClient creates a new pro Client -func NewClient() *client.Client { - return client.NewClient(httpClient, PrepareProRequestWithOptions) -} - -// newUserWithClient creates a new user via Pro API, and updates local cache -// using the specified http client. -func newUserWithClient(uc common.UserConfig, hc *http.Client) (*client.User, error) { - deviceID := uc.GetDeviceID() - logger.Debugf("Creating new user with device ID '%v'", deviceID) - - // use deviceID, ignore userID, token - user := common.NewUserConfigData(uc.GetAppName(), deviceID, 0, "", uc.GetInternalHeaders(), uc.GetLanguage()) - resp, err := client.NewClient(hc, PrepareProRequestWithOptions).UserCreate(user) - if err != nil { - return nil, err - } - setUserData(resp.User.Auth.ID, &resp.User) - logger.Debugf("created user %+v", resp.User) - return &resp.User, nil -} - -// FetchUserData fetches user data from Pro API, and updates local cache. -func FetchUserData(uc common.UserConfig) (*client.User, error) { - return fetchUserDataWithClient(uc, httpClient) -} - -func fetchUserDataWithClient(uc common.UserConfig, hc *http.Client) (*client.User, error) { - userID := uc.GetUserID() - logger.Debugf("Fetching user status with device ID '%v', user ID '%v' and proToken %v", uc.GetDeviceID(), userID, uc.GetToken()) - - resp, err := client.NewClient(hc, PrepareProRequestWithOptions).UserData(uc) - if err != nil { - return nil, err - } - setUserData(userID, &resp.User) - logger.Debugf("User %d is '%v'", userID, resp.User.UserStatus) - return &resp.User, nil -} - -func setUserData(userID int64, user *client.User) { - logger.Debugf("Storing user data for user %v", userID) - userData.save(userID, user) -} diff --git a/pro/user_data_test.go b/pro/user_data_test.go deleted file mode 100644 index f4f24c62c..000000000 --- a/pro/user_data_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package pro - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/getlantern/flashlight/v7/common" - "github.com/getlantern/flashlight/v7/pro/client" -) - -func TestUsers(t *testing.T) { - common.ForceStaging() - - deviceID := "77777777" - u, err := newUserWithClient(common.NewUserConfigData(common.DefaultAppName, deviceID, 0, "", nil, "en-US"), nil) - - assert.NoError(t, err, "Unexpected error") - assert.NotNil(t, u, "Should have gotten a user") - t.Logf("user: %+v", u) - - uc := common.NewUserConfigData(common.DefaultAppName, deviceID, u.Auth.ID, u.Auth.Token, nil, "en-US") - u, err = fetchUserDataWithClient(uc, nil) - assert.NoError(t, err, "Unexpected error") - assert.NotNil(t, u, "Should have gotten a user") - - delete(userData.data, u.ID) - - u, err = fetchUserDataWithClient(uc, nil) - assert.NoError(t, err, "Unexpected error") - assert.NotNil(t, u, "Should have gotten a user") - - pro, _ := IsProUser(uc) - assert.False(t, pro) - pro, _ = IsProUserFast(uc) - assert.False(t, pro) - - var waitUser int64 = 88888 - var changed int - var userDataSaved int - OnUserData(func(*client.User, *client.User) { - userDataSaved += 1 - }) - - OnProStatusChange(func(bool, bool) { - changed += 1 - }) - - userData.save(waitUser, u) - assert.Equal(t, 1, userDataSaved, "OnUserData should be called") - assert.Equal(t, 1, changed, "OnProStatusChange should be called") - - userData.save(waitUser, u) - assert.Equal(t, 2, userDataSaved, "OnUserData should be called after each saving") - assert.Equal(t, 1, changed, "OnProStatusChange should not be called again if nothing changes") - -} From a781c81ffb2314a61152c46358edbf85cfaa4651 Mon Sep 17 00:00:00 2001 From: atavism Date: Mon, 8 Apr 2024 14:29:40 -0700 Subject: [PATCH 04/10] Update pro client --- pro/http.go | 29 +++++++++ pro/proxy.go | 155 +++++++++++++++++++++++++++++++++++++++++++++++ pro/user_data.go | 95 +++++++++++++++++++++++++++++ 3 files changed, 279 insertions(+) create mode 100644 pro/http.go create mode 100644 pro/proxy.go create mode 100644 pro/user_data.go diff --git a/pro/http.go b/pro/http.go new file mode 100644 index 000000000..ce765cd5b --- /dev/null +++ b/pro/http.go @@ -0,0 +1,29 @@ +package pro + +import ( + "net/http" + "time" + + "github.com/getlantern/flashlight/v7/proxied" +) + +var ( + httpClient = getHTTPClient(proxied.ParallelForIdempotent()) +) + +// GetHTTPClient creates a new http.Client that uses domain fronting and direct +// proxies. +func GetHTTPClient() *http.Client { + return httpClient +} + +func getHTTPClient(rt http.RoundTripper) *http.Client { + return &http.Client{ + Transport: rt, + // Don't follow redirects + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + Timeout: 30 * time.Second, + } +} diff --git a/pro/proxy.go b/pro/proxy.go new file mode 100644 index 000000000..73f45ac62 --- /dev/null +++ b/pro/proxy.go @@ -0,0 +1,155 @@ +package pro + +import ( + "bytes" + "compress/gzip" + "encoding/json" + "io" + "io/ioutil" + "net/http" + "net/http/httputil" + "strconv" + "strings" + + "github.com/getlantern/flashlight/v7/common" + "github.com/getlantern/golog" +) + +var ( + log = golog.LoggerFor("flashlight.pro") +) + +type proxyTransport struct { + // Satisfies http.RoundTripper +} + +func (pt *proxyTransport) processOptions(req *http.Request) *http.Response { + resp := &http.Response{ + StatusCode: http.StatusOK, + Header: http.Header{ + "Connection": {"keep-alive"}, + "Via": {"Lantern Client"}, + }, + Body: ioutil.NopCloser(strings.NewReader("preflight complete")), + } + if !common.ProcessCORS(resp.Header, req) { + return &http.Response{ + StatusCode: http.StatusForbidden, + } + } + return resp +} + +func (pt *proxyTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) { + if req.Method == "OPTIONS" { + // No need to proxy the OPTIONS request. + return pt.processOptions(req), nil + } + origin := req.Header.Get("Origin") + // Workaround for https://github.com/getlantern/pro-server/issues/192 + req.Header.Del("Origin") + resp, err = GetHTTPClient().Do(req) + if err != nil { + log.Errorf("Could not issue HTTP request? %v", err) + return + } + + // Put the header back for subsequent CORS processing. + req.Header.Set("Origin", origin) + common.ProcessCORS(resp.Header, req) + if req.URL.Path != "/user-data" || resp.StatusCode != http.StatusOK { + return + } + // Try to update user data implicitly + _userID := req.Header.Get("X-Lantern-User-Id") + if _userID == "" { + log.Error("Request has an empty user ID") + return + } + userID, parseErr := strconv.ParseInt(_userID, 10, 64) + if parseErr != nil { + log.Errorf("User ID %s is invalid", _userID) + return + } + body, readErr := ioutil.ReadAll(resp.Body) + if readErr != nil { + log.Errorf("Error read response body: %v", readErr) + return + } + resp.Body = ioutil.NopCloser(bytes.NewReader(body)) + encoding := resp.Header.Get("Content-Encoding") + var br io.Reader = bytes.NewReader(body) + switch encoding { + case "gzip": + gzr, readErr := gzip.NewReader(bytes.NewReader(body)) + if readErr != nil { + log.Errorf("Unable to decode gzipped data: %v", readErr) + return + } + br = gzr + case "": + default: + log.Errorf("Unsupported response encoding %s", encoding) + return + } + user := User{} + readErr = json.NewDecoder(br).Decode(&user) + if readErr != nil { + log.Errorf("Error decoding JSON: %v", readErr) + return + } + log.Debugf("Updating user data implicitly for user %v", userID) + setUserData(userID, &user) + return +} + +// PrepareProRequestWithOptions normalizes requests to the pro server with +// device ID, user ID, etc set. +func PrepareProRequestWithOptions(r *http.Request, uc common.UserConfig) { + prepareProRequest(r, uc, true) +} + +// PrepareProRequest normalizes requests to the pro server without overwriting +// device ID, user ID, etc. +func PrepareProRequest(r *http.Request, uc common.UserConfig) { + prepareProRequest(r, uc, false) +} + +func prepareProRequest(r *http.Request, uc common.UserConfig, options bool) { + r.URL.Scheme = "http" + r.URL.Host = common.ProAPIHost + // XXX <03-02-22, soltzen> Requests coming from lantern-desktop's UI client + // will always carry lantern-desktop's server address (i.e., + // [here](https://github.com/getlantern/lantern-desktop/blob/87370cca9c895d0e0296b4d16e292ad8adbdae33/server/defaults_static.go#L1)) + // in their 'Host' header (like this: 'Host: localhost:16823'). This is + // problamatic for many servers (Replica's as well). So, best to either + // wipe it or assign it as the URL's host + r.Host = r.URL.Host + r.RequestURI = "" // http: Request.RequestURI can't be set in client requests. + r.Header.Set("Access-Control-Allow-Headers", strings.Join([]string{ + common.DeviceIdHeader, + common.ProTokenHeader, + common.UserIdHeader, + }, ", ")) + + // Add auth headers only if not present, to avoid race conditions + // when creating new user or switching user, i.e., linking device + // to a new account. (ovewriteAuth=false) + common.AddCommonHeadersWithOptions(uc, r, options) +} + +// APIHandler returns an HTTP handler that specifically looks for and properly +// handles pro server requests. +func APIHandler(uc common.UserConfig) http.Handler { + log.Debugf("Returning pro API handler hitting host: %v", common.ProAPIHost) + return &httputil.ReverseProxy{ + Transport: &proxyTransport{}, + Director: func(r *http.Request) { + // Strip /pro from path. + if strings.HasPrefix(r.URL.Path, "/pro/") { + r.URL.Path = r.URL.Path[4:] + } + PrepareProRequest(r, uc) + }, + } +} diff --git a/pro/user_data.go b/pro/user_data.go new file mode 100644 index 000000000..74dd691a0 --- /dev/null +++ b/pro/user_data.go @@ -0,0 +1,95 @@ +package pro + +import ( + "sync" + + "github.com/getlantern/eventual" + "github.com/getlantern/flashlight/v7/common" + "github.com/getlantern/golog" +) + +var logger = golog.LoggerFor("flashlight.app.pro") + +type userMap struct { + sync.RWMutex + data map[int64]eventual.Value + onUserData []func(current *User, new *User) +} + +var userData = userMap{ + data: make(map[int64]eventual.Value), + onUserData: make([]func(current *User, new *User), 0), +} + +// OnUserData allows registering an event handler to learn when the +// user data has been fetched. +func OnUserData(cb func(current *User, new *User)) { + userData.Lock() + userData.onUserData = append(userData.onUserData, cb) + userData.Unlock() +} + +// OnProStatusChange allows registering an event handler to learn when the +// user's pro status or "yinbi enabled" status has changed. +func OnProStatusChange(cb func(isPro bool, yinbiEnabled bool)) { + OnUserData(func(current *User, new *User) { + if current == nil || + isActive(current.UserStatus) != isActive(new.UserStatus) || + current.YinbiEnabled != new.YinbiEnabled { + cb(isActive(new.UserStatus), new.YinbiEnabled) + } + }) +} + +func (m *userMap) save(userID int64, u *User) { + m.Lock() + v := m.data[userID] + var current *User + if v == nil { + v = eventual.NewValue() + } else { + cur, _ := v.Get(0) + current, _ = cur.(*User) + } + v.Set(u) + m.data[userID] = v + onUserData := m.onUserData + m.Unlock() + for _, cb := range onUserData { + cb(current, u) + } +} + +func (m *userMap) get(userID int64) (*User, bool) { + m.RLock() + v := m.data[userID] + m.RUnlock() + if v == nil { + return nil, false + } + u, valid := v.Get(0) + if !valid { + return nil, false + } + return u.(*User), true +} + +// IsProUserFast indicates whether or not the user is pro and whether or not the +// user's status is know, never calling the Pro API to determine the status. +func IsProUserFast(uc common.UserConfig) (isPro bool, statusKnown bool) { + user, found := GetUserDataFast(uc.GetUserID()) + if !found { + return false, false + } + return isActive(user.UserStatus), found +} + +// isActive determines whether the given status is an active status +func isActive(status string) bool { + return status == "active" +} + +// GetUserDataFast gets the user data for the given userID if found. +func GetUserDataFast(userID int64) (*User, bool) { + return userData.get(userID) +} From 9814ddae2a603e020e5d4fb630c40c27fa79318b Mon Sep 17 00:00:00 2001 From: atavism Date: Mon, 8 Apr 2024 14:29:44 -0700 Subject: [PATCH 05/10] Update pro client --- pro/user.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 pro/user.go diff --git a/pro/user.go b/pro/user.go new file mode 100644 index 000000000..246613e44 --- /dev/null +++ b/pro/user.go @@ -0,0 +1,26 @@ +package pro + +type Device struct { + Id string `json:"id"` + Name string `json:"name"` + Created int64 `json:"created"` +} + +type Auth struct { + ID int64 `json:"userId"` + Token string `json:"token"` +} + +type User struct { + Auth `json:",inline"` + Email string `json:"email"` + PhoneNumber string `json:"telephone"` + UserStatus string `json:"userStatus"` + Locale string `json:"locale"` + Expiration int64 `json:"expiration"` + Devices []Device `json:"devices"` + Code string `json:"code"` + ExpireAt int64 `json:"expireAt"` + Referral string `json:"referral"` + YinbiEnabled bool `json:"yinbiEnabled"` +} From 52821ac5bc6236c1e3ba48ebb63e057c249d63b1 Mon Sep 17 00:00:00 2001 From: atavism Date: Mon, 8 Apr 2024 14:33:39 -0700 Subject: [PATCH 06/10] Add setUserData --- pro/user_data.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pro/user_data.go b/pro/user_data.go index 74dd691a0..d71a79ade 100644 --- a/pro/user_data.go +++ b/pro/user_data.go @@ -93,3 +93,8 @@ func isActive(status string) bool { func GetUserDataFast(userID int64) (*User, bool) { return userData.get(userID) } + +func setUserData(userID int64, user *User) { + logger.Debugf("Storing user data for user %v", userID) + userData.save(userID, user) +} From d86cdc2f9dc7888d1d47e7be53040559570b54dd Mon Sep 17 00:00:00 2001 From: atavism Date: Wed, 10 Apr 2024 14:02:46 -0700 Subject: [PATCH 07/10] remove unused user data code --- pro/user_data.go | 100 ----------------------------------------------- 1 file changed, 100 deletions(-) delete mode 100644 pro/user_data.go diff --git a/pro/user_data.go b/pro/user_data.go deleted file mode 100644 index d71a79ade..000000000 --- a/pro/user_data.go +++ /dev/null @@ -1,100 +0,0 @@ -package pro - -import ( - "sync" - - "github.com/getlantern/eventual" - "github.com/getlantern/flashlight/v7/common" - "github.com/getlantern/golog" -) - -var logger = golog.LoggerFor("flashlight.app.pro") - -type userMap struct { - sync.RWMutex - data map[int64]eventual.Value - onUserData []func(current *User, new *User) -} - -var userData = userMap{ - data: make(map[int64]eventual.Value), - onUserData: make([]func(current *User, new *User), 0), -} - -// OnUserData allows registering an event handler to learn when the -// user data has been fetched. -func OnUserData(cb func(current *User, new *User)) { - userData.Lock() - userData.onUserData = append(userData.onUserData, cb) - userData.Unlock() -} - -// OnProStatusChange allows registering an event handler to learn when the -// user's pro status or "yinbi enabled" status has changed. -func OnProStatusChange(cb func(isPro bool, yinbiEnabled bool)) { - OnUserData(func(current *User, new *User) { - if current == nil || - isActive(current.UserStatus) != isActive(new.UserStatus) || - current.YinbiEnabled != new.YinbiEnabled { - cb(isActive(new.UserStatus), new.YinbiEnabled) - } - }) -} - -func (m *userMap) save(userID int64, u *User) { - m.Lock() - v := m.data[userID] - var current *User - if v == nil { - v = eventual.NewValue() - } else { - cur, _ := v.Get(0) - current, _ = cur.(*User) - } - v.Set(u) - m.data[userID] = v - onUserData := m.onUserData - m.Unlock() - for _, cb := range onUserData { - cb(current, u) - } -} - -func (m *userMap) get(userID int64) (*User, bool) { - m.RLock() - v := m.data[userID] - m.RUnlock() - if v == nil { - return nil, false - } - u, valid := v.Get(0) - if !valid { - return nil, false - } - return u.(*User), true -} - -// IsProUserFast indicates whether or not the user is pro and whether or not the -// user's status is know, never calling the Pro API to determine the status. -func IsProUserFast(uc common.UserConfig) (isPro bool, statusKnown bool) { - user, found := GetUserDataFast(uc.GetUserID()) - if !found { - return false, false - } - return isActive(user.UserStatus), found -} - -// isActive determines whether the given status is an active status -func isActive(status string) bool { - return status == "active" -} - -// GetUserDataFast gets the user data for the given userID if found. -func GetUserDataFast(userID int64) (*User, bool) { - return userData.get(userID) -} - -func setUserData(userID int64, user *User) { - logger.Debugf("Storing user data for user %v", userID) - userData.save(userID, user) -} From 5bc34dfa1a46f576d3d33d83ec70be5dda88ea75 Mon Sep 17 00:00:00 2001 From: atavism Date: Wed, 10 Apr 2024 14:12:33 -0700 Subject: [PATCH 08/10] remove pro package --- client/handler.go | 25 ------------------------- pro/http.go | 29 ----------------------------- 2 files changed, 54 deletions(-) delete mode 100644 pro/http.go diff --git a/client/handler.go b/client/handler.go index 912b69b35..f783474f4 100644 --- a/client/handler.go +++ b/client/handler.go @@ -13,9 +13,7 @@ import ( "github.com/getlantern/proxy/v3/filters" "github.com/getlantern/flashlight/v7/chained" - "github.com/getlantern/flashlight/v7/common" "github.com/getlantern/flashlight/v7/ops" - "github.com/getlantern/flashlight/v7/pro" ) func (client *Client) handle(conn net.Conn) error { @@ -62,11 +60,6 @@ func (client *Client) filter(cs *filters.ConnectionState, req *http.Request, nex req.URL.Scheme = "http" req.URL.Host = req.Host - if common.Platform == "android" && req.URL != nil && req.URL.Host == "localhost" && - strings.HasPrefix(req.URL.Path, "/pro/") { - return client.interceptProRequest(cs, req) - } - op, ok := client.opsMap.get(cs.Downstream()) if ok { op.UserAgent(req.Header.Get("User-Agent")).OriginFromRequest(req) @@ -154,24 +147,6 @@ func (client *Client) isHTTPProxyPort(r *http.Request) bool { return false } -// interceptProRequest specifically looks for and properly handles pro server -// requests (similar to desktop's APIHandler) -func (client *Client) interceptProRequest(cs *filters.ConnectionState, r *http.Request) (*http.Response, *filters.ConnectionState, error) { - log.Debugf("Intercepting request to pro server: %v", r.URL.Path) - r.URL.Path = r.URL.Path[4:] - pro.PrepareProRequest(r, client.user) - r.Header.Del("Origin") - resp, err := pro.GetHTTPClient().Do(r) - if err != nil { - log.Errorf("Error intercepting request to pro server: %v", err) - resp = &http.Response{ - StatusCode: http.StatusInternalServerError, - Close: true, - } - } - return filters.ShortCircuit(cs, r, resp) -} - func (client *Client) easyblock(cs *filters.ConnectionState, req *http.Request) (*http.Response, *filters.ConnectionState, error) { log.Debugf("Blocking %v on %v", req.URL, req.Host) client.statsTracker.IncAdsBlocked() diff --git a/pro/http.go b/pro/http.go deleted file mode 100644 index ce765cd5b..000000000 --- a/pro/http.go +++ /dev/null @@ -1,29 +0,0 @@ -package pro - -import ( - "net/http" - "time" - - "github.com/getlantern/flashlight/v7/proxied" -) - -var ( - httpClient = getHTTPClient(proxied.ParallelForIdempotent()) -) - -// GetHTTPClient creates a new http.Client that uses domain fronting and direct -// proxies. -func GetHTTPClient() *http.Client { - return httpClient -} - -func getHTTPClient(rt http.RoundTripper) *http.Client { - return &http.Client{ - Transport: rt, - // Don't follow redirects - CheckRedirect: func(req *http.Request, via []*http.Request) error { - return http.ErrUseLastResponse - }, - Timeout: 30 * time.Second, - } -} From 6f6563b59ae69df6b14d42cb85faffcca2ef48d7 Mon Sep 17 00:00:00 2001 From: atavism Date: Wed, 10 Apr 2024 14:16:33 -0700 Subject: [PATCH 09/10] update errors package --- go.mod | 4 ++-- go.sum | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index c46532360..5e4f11a33 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/getlantern/flashlight/v7 -go 1.21 +go 1.22.0 replace github.com/elazarl/goproxy => github.com/getlantern/goproxy v0.0.0-20220805074304-4a43a9ed4ec6 @@ -39,7 +39,7 @@ require ( github.com/getlantern/dnsgrab v0.0.0-20211216020425-5d5e155a01a8 github.com/getlantern/domains v0.0.0-20220311111720-94f59a903271 github.com/getlantern/ema v0.0.0-20190620044903-5943d28f40e4 - github.com/getlantern/errors v1.0.3 + github.com/getlantern/errors v1.0.5-0.20240410211607-f268a297d5d1 github.com/getlantern/event v0.0.0-20210901195647-a7e3145142e6 github.com/getlantern/eventual v1.0.0 github.com/getlantern/eventual/v2 v2.0.2 diff --git a/go.sum b/go.sum index 290da5772..92885beb3 100644 --- a/go.sum +++ b/go.sum @@ -242,6 +242,10 @@ github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7/go.mod h1:l+xpFB github.com/getlantern/errors v1.0.1/go.mod h1:l+xpFBrCtDLpK9qNjxs+cHU6+BAdlBaxHqikB6Lku3A= github.com/getlantern/errors v1.0.3 h1:Ne4Ycj7NI1BtSyAfVeAT/DNoxz7/S2BUc3L2Ht1YSHE= github.com/getlantern/errors v1.0.3/go.mod h1:m8C7H1qmouvsGpwQqk/6NUpIVMpfzUPn608aBZDYV04= +github.com/getlantern/errors v1.0.5-0.20240410211410-efcb55d54ffb h1:I8oXS6xtVXtxq5RBpAkxV8tyrS6dq5akyBZsnkzozns= +github.com/getlantern/errors v1.0.5-0.20240410211410-efcb55d54ffb/go.mod h1:L1h+WK2Enz9MzoHsyGpdtQlwXe7U/ANbSM4rEbAl3N8= +github.com/getlantern/errors v1.0.5-0.20240410211607-f268a297d5d1 h1:06/WReVGjGazEKDQcT/OADWkhr/EQY3Q8TdtLCZfu5E= +github.com/getlantern/errors v1.0.5-0.20240410211607-f268a297d5d1/go.mod h1:L1h+WK2Enz9MzoHsyGpdtQlwXe7U/ANbSM4rEbAl3N8= github.com/getlantern/event v0.0.0-20210901195647-a7e3145142e6 h1:sjFsoQHJqzDiwgbOLHnG/zYIpN1Sbmv/7gk1ie/KkHg= github.com/getlantern/event v0.0.0-20210901195647-a7e3145142e6/go.mod h1:iToZ3dqm/iFxRHPHUHUrF1JZtg0e06ZSXD1BuiGoUaY= github.com/getlantern/eventual v0.0.0-20180125201821-84b02499361b/go.mod h1:O8T3zFEcY6+LRXFcVV4q8mEu2tDIixG8edC84DfswBc= From 7fa504fecf8d1ac9066387f5f81b366bff5d8271 Mon Sep 17 00:00:00 2001 From: atavism Date: Wed, 10 Apr 2024 14:20:13 -0700 Subject: [PATCH 10/10] remove pro package --- pro/proxy.go | 155 --------------------------------------------------- pro/user.go | 26 --------- 2 files changed, 181 deletions(-) delete mode 100644 pro/proxy.go delete mode 100644 pro/user.go diff --git a/pro/proxy.go b/pro/proxy.go deleted file mode 100644 index 73f45ac62..000000000 --- a/pro/proxy.go +++ /dev/null @@ -1,155 +0,0 @@ -package pro - -import ( - "bytes" - "compress/gzip" - "encoding/json" - "io" - "io/ioutil" - "net/http" - "net/http/httputil" - "strconv" - "strings" - - "github.com/getlantern/flashlight/v7/common" - "github.com/getlantern/golog" -) - -var ( - log = golog.LoggerFor("flashlight.pro") -) - -type proxyTransport struct { - // Satisfies http.RoundTripper -} - -func (pt *proxyTransport) processOptions(req *http.Request) *http.Response { - resp := &http.Response{ - StatusCode: http.StatusOK, - Header: http.Header{ - "Connection": {"keep-alive"}, - "Via": {"Lantern Client"}, - }, - Body: ioutil.NopCloser(strings.NewReader("preflight complete")), - } - if !common.ProcessCORS(resp.Header, req) { - return &http.Response{ - StatusCode: http.StatusForbidden, - } - } - return resp -} - -func (pt *proxyTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) { - if req.Method == "OPTIONS" { - // No need to proxy the OPTIONS request. - return pt.processOptions(req), nil - } - origin := req.Header.Get("Origin") - // Workaround for https://github.com/getlantern/pro-server/issues/192 - req.Header.Del("Origin") - resp, err = GetHTTPClient().Do(req) - if err != nil { - log.Errorf("Could not issue HTTP request? %v", err) - return - } - - // Put the header back for subsequent CORS processing. - req.Header.Set("Origin", origin) - common.ProcessCORS(resp.Header, req) - if req.URL.Path != "/user-data" || resp.StatusCode != http.StatusOK { - return - } - // Try to update user data implicitly - _userID := req.Header.Get("X-Lantern-User-Id") - if _userID == "" { - log.Error("Request has an empty user ID") - return - } - userID, parseErr := strconv.ParseInt(_userID, 10, 64) - if parseErr != nil { - log.Errorf("User ID %s is invalid", _userID) - return - } - body, readErr := ioutil.ReadAll(resp.Body) - if readErr != nil { - log.Errorf("Error read response body: %v", readErr) - return - } - resp.Body = ioutil.NopCloser(bytes.NewReader(body)) - encoding := resp.Header.Get("Content-Encoding") - var br io.Reader = bytes.NewReader(body) - switch encoding { - case "gzip": - gzr, readErr := gzip.NewReader(bytes.NewReader(body)) - if readErr != nil { - log.Errorf("Unable to decode gzipped data: %v", readErr) - return - } - br = gzr - case "": - default: - log.Errorf("Unsupported response encoding %s", encoding) - return - } - user := User{} - readErr = json.NewDecoder(br).Decode(&user) - if readErr != nil { - log.Errorf("Error decoding JSON: %v", readErr) - return - } - log.Debugf("Updating user data implicitly for user %v", userID) - setUserData(userID, &user) - return -} - -// PrepareProRequestWithOptions normalizes requests to the pro server with -// device ID, user ID, etc set. -func PrepareProRequestWithOptions(r *http.Request, uc common.UserConfig) { - prepareProRequest(r, uc, true) -} - -// PrepareProRequest normalizes requests to the pro server without overwriting -// device ID, user ID, etc. -func PrepareProRequest(r *http.Request, uc common.UserConfig) { - prepareProRequest(r, uc, false) -} - -func prepareProRequest(r *http.Request, uc common.UserConfig, options bool) { - r.URL.Scheme = "http" - r.URL.Host = common.ProAPIHost - // XXX <03-02-22, soltzen> Requests coming from lantern-desktop's UI client - // will always carry lantern-desktop's server address (i.e., - // [here](https://github.com/getlantern/lantern-desktop/blob/87370cca9c895d0e0296b4d16e292ad8adbdae33/server/defaults_static.go#L1)) - // in their 'Host' header (like this: 'Host: localhost:16823'). This is - // problamatic for many servers (Replica's as well). So, best to either - // wipe it or assign it as the URL's host - r.Host = r.URL.Host - r.RequestURI = "" // http: Request.RequestURI can't be set in client requests. - r.Header.Set("Access-Control-Allow-Headers", strings.Join([]string{ - common.DeviceIdHeader, - common.ProTokenHeader, - common.UserIdHeader, - }, ", ")) - - // Add auth headers only if not present, to avoid race conditions - // when creating new user or switching user, i.e., linking device - // to a new account. (ovewriteAuth=false) - common.AddCommonHeadersWithOptions(uc, r, options) -} - -// APIHandler returns an HTTP handler that specifically looks for and properly -// handles pro server requests. -func APIHandler(uc common.UserConfig) http.Handler { - log.Debugf("Returning pro API handler hitting host: %v", common.ProAPIHost) - return &httputil.ReverseProxy{ - Transport: &proxyTransport{}, - Director: func(r *http.Request) { - // Strip /pro from path. - if strings.HasPrefix(r.URL.Path, "/pro/") { - r.URL.Path = r.URL.Path[4:] - } - PrepareProRequest(r, uc) - }, - } -} diff --git a/pro/user.go b/pro/user.go deleted file mode 100644 index 246613e44..000000000 --- a/pro/user.go +++ /dev/null @@ -1,26 +0,0 @@ -package pro - -type Device struct { - Id string `json:"id"` - Name string `json:"name"` - Created int64 `json:"created"` -} - -type Auth struct { - ID int64 `json:"userId"` - Token string `json:"token"` -} - -type User struct { - Auth `json:",inline"` - Email string `json:"email"` - PhoneNumber string `json:"telephone"` - UserStatus string `json:"userStatus"` - Locale string `json:"locale"` - Expiration int64 `json:"expiration"` - Devices []Device `json:"devices"` - Code string `json:"code"` - ExpireAt int64 `json:"expireAt"` - Referral string `json:"referral"` - YinbiEnabled bool `json:"yinbiEnabled"` -}