Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions pkg/code/server/grpc/messaging/message_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package messaging
import (
"bytes"
"context"
"math"
"time"

"github.com/mr-tron/base58"
Expand All @@ -22,6 +23,7 @@ import (
"github.com/code-payments/code-server/pkg/code/limit"
"github.com/code-payments/code-server/pkg/code/thirdparty"
currency_lib "github.com/code-payments/code-server/pkg/currency"
"github.com/code-payments/code-server/pkg/kin"
)

// MessageHandler provides message-specific in addition to the generic message
Expand Down Expand Up @@ -138,14 +140,21 @@ func (h *RequestToReceiveBillMessageHandler) Validate(ctx context.Context, rende
quarks = &typed.Exact.Quarks

if currency != currency_lib.KIN {
return newMessageValidationError("exact exchange data only supports kin currency")
return newMessageValidationError("exact exchange data is reserved for kin only")
}

if nativeAmount != math.Trunc(nativeAmount) {
return newMessageValidationError("native amount can't include fractional kin")
}
if *quarks%kin.QuarksPerKin != 0 {
return newMessageValidationError("quark amount can't include fractional kin")
}
case *messagingpb.RequestToReceiveBill_Partial:
currency = currency_lib.Code(typed.Partial.Currency)
nativeAmount = typed.Partial.NativeAmount

if currency == currency_lib.KIN {
return newMessageValidationError("partial exchange data only supports fiat currencies")
return newMessageValidationError("partial exchange data is reserved for fiat currencies")
}
default:
return newMessageValidationError("exchange data is nil")
Expand Down
18 changes: 16 additions & 2 deletions pkg/code/server/grpc/messaging/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -420,10 +420,24 @@ func TestSendMessage_RequestToReceiveBill_KinValue_Validation(t *testing.T) {
env.server1.assertNoMessages(t, rendezvousKey)
env.server1.assertPaymentRequestRecordNotSaved(t, rendezvousKey)

env.client1.resetConf()
env.client1.conf.simulateFractionalNativeAmount = true
sendMessageCall = env.client1.sendRequestToReceiveKinBillMessage(t, rendezvousKey, false, false, true)
sendMessageCall.assertInvalidMessageError(t, "native amount can't include fractional kin")
env.server1.assertNoMessages(t, rendezvousKey)
env.server1.assertPaymentRequestRecordNotSaved(t, rendezvousKey)

env.client1.resetConf()
env.client1.conf.simulateFractionalQuarkAmount = true
sendMessageCall = env.client1.sendRequestToReceiveKinBillMessage(t, rendezvousKey, false, false, true)
sendMessageCall.assertInvalidMessageError(t, "quark amount can't include fractional kin")
env.server1.assertNoMessages(t, rendezvousKey)
env.server1.assertPaymentRequestRecordNotSaved(t, rendezvousKey)

env.client1.resetConf()
env.client1.conf.simulateInvalidCurrency = true
sendMessageCall = env.client1.sendRequestToReceiveKinBillMessage(t, rendezvousKey, false, false, true)
sendMessageCall.assertInvalidMessageError(t, "exact exchange data only supports kin currency")
sendMessageCall.assertInvalidMessageError(t, "exact exchange data is reserved for kin only")
env.server1.assertNoMessages(t, rendezvousKey)
env.server1.assertPaymentRequestRecordNotSaved(t, rendezvousKey)

Expand Down Expand Up @@ -519,7 +533,7 @@ func TestSendMessage_RequestToReceiveBill_FiatValue_Validation(t *testing.T) {
env.client1.resetConf()
env.client1.conf.simulateInvalidCurrency = true
sendMessageCall = env.client1.sendRequestToReceiveFiatBillMessage(t, rendezvousKey, false, false, true)
sendMessageCall.assertInvalidMessageError(t, "partial exchange data only supports fiat currencies")
sendMessageCall.assertInvalidMessageError(t, "partial exchange data is reserved for fiat currencies")
env.server1.assertNoMessages(t, rendezvousKey)
env.server1.assertPaymentRequestRecordNotSaved(t, rendezvousKey)

Expand Down
30 changes: 19 additions & 11 deletions pkg/code/server/grpc/messaging/testutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,11 +234,13 @@ type clientConf struct {

// Simulations for invalid exchange data

simulateInvalidCurrency bool
simulateInvalidExchangeRate bool
simulateInvalidNativeAmount bool
simulateSmallNativeAmount bool
simulateLargeNativeAmount bool
simulateInvalidCurrency bool
simulateInvalidExchangeRate bool
simulateInvalidNativeAmount bool
simulateSmallNativeAmount bool
simulateLargeNativeAmount bool
simulateFractionalNativeAmount bool
simulateFractionalQuarkAmount bool

// Simulations for invalid relationships

Expand Down Expand Up @@ -588,16 +590,16 @@ func (c *clientEnv) sendRequestToReceiveKinBillMessage(t *testing.T, rendezvousK
exchangeData := &transactionpb.ExchangeData{
Currency: "kin",
ExchangeRate: 1.0,
NativeAmount: 10_000,
Quarks: kin.ToQuarks(10_000),
NativeAmount: 10_001,
Quarks: kin.ToQuarks(10_001),
}

if c.conf.simulateInvalidCurrency {
exchangeData.Currency = "usd"
}
if c.conf.simulateInvalidExchangeRate {
exchangeData.ExchangeRate *= 1.5
exchangeData.NativeAmount *= 1.5
exchangeData.ExchangeRate *= 2.0
exchangeData.NativeAmount *= 2.0
}
if c.conf.simulateInvalidNativeAmount {
exchangeData.NativeAmount += 2
Expand All @@ -607,8 +609,14 @@ func (c *clientEnv) sendRequestToReceiveKinBillMessage(t *testing.T, rendezvousK
exchangeData.Quarks = kin.ToQuarks(1)
}
if c.conf.simulateLargeNativeAmount {
exchangeData.NativeAmount = 100001
exchangeData.Quarks = kin.ToQuarks(100001)
exchangeData.NativeAmount = 100_001
exchangeData.Quarks = kin.ToQuarks(100_001)
}
if c.conf.simulateFractionalNativeAmount {
exchangeData.NativeAmount += 0.1
}
if c.conf.simulateFractionalQuarkAmount {
exchangeData.Quarks += kin.QuarksPerKin / 10
}

msg := &messagingpb.RequestToReceiveBill{
Expand Down
47 changes: 1 addition & 46 deletions pkg/code/server/web/paymentrequest/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ func newTrustlessPaymentRequestFromHttpContext(r *http.Request) (*trustlessPayme
return nil, errors.New("intent is not a public key")
}

// Validation occurs at the messaging service
var protoMesage messagingpb.RequestToReceiveBill
messageBytes, err := base64.RawURLEncoding.DecodeString(httpRequestBody.Message)
if err != nil {
Expand All @@ -245,52 +246,6 @@ func newTrustlessPaymentRequestFromHttpContext(r *http.Request) (*trustlessPayme
}
copy(signature[:], decodedSignature)

_, err = common.NewAccountFromProto(protoMesage.RequestorAccount)
if err != nil {
return nil, errors.New("destination is not a public key")
}

var currency currency_lib.Code
var amount float64
switch typed := protoMesage.ExchangeData.(type) {
case *messagingpb.RequestToReceiveBill_Exact:
currency = currency_lib.Code(strings.ToLower(typed.Exact.Currency))
amount = float64(kin.FromQuarks(typed.Exact.Quarks)) // Because of minimum bucket sizes

if currency != currency_lib.KIN {
return nil, errors.New("exact exchange data is reserved for kin only")
}

if typed.Exact.ExchangeRate != 1.0 {
return nil, errors.New("kin exchange rate must be 1.0")
} else if kin.ToQuarks(uint64(amount)) != typed.Exact.Quarks {
return nil, errors.New("kin amount cannot be fractional")
} else if amount != typed.Exact.NativeAmount {
return nil, errors.New("kin amount doesn't match quarks")
}
case *messagingpb.RequestToReceiveBill_Partial:
currency = currency_lib.Code(strings.ToLower(typed.Partial.Currency))
amount = typed.Partial.NativeAmount

if currency == currency_lib.KIN {
return nil, errors.New("partial exchange data is reserved for fiat currencies")
}
default:
return nil, errors.New("exchange data not provided")
}

limits, ok := limit.MicroPaymentLimits[currency]
if !ok {
return nil, errors.Errorf("%s currency is not currently supported", currency)
} else if amount > limits.Max {
return nil, errors.Errorf("%s currency has a maximum amount of %.2f", currency, limits.Max)
} else if amount < limits.Min {
return nil, errors.Errorf("%s currency has a minimum amount of %.2f", currency, limits.Min)
}

// todo: Validate domain fields with user-friendly error messaging. The
// messaging service will do this for now, and will be translated.

if httpRequestBody.Webhook != nil {
err = netutil.ValidateHttpUrl(*httpRequestBody.Webhook, true, false)
if err != nil {
Expand Down