From 3189ca0cb2a36b93d16cca26788302b2873b9475 Mon Sep 17 00:00:00 2001 From: Tom Kay Date: Thu, 15 Aug 2024 16:53:22 +0100 Subject: [PATCH 01/27] PreferNetworkToken on attempt config (#206) --- v1/scheduler/attempt_config.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/v1/scheduler/attempt_config.go b/v1/scheduler/attempt_config.go index 21737f8..3e103a6 100644 --- a/v1/scheduler/attempt_config.go +++ b/v1/scheduler/attempt_config.go @@ -26,4 +26,6 @@ type AttemptConfig struct { OverridePoolConnectorIDs []string `json:"overridePoolConnectorIDs,omitempty" yaml:"overridePoolConnectorIDs,omitempty" validate:"dive,lowercase"` Prefer3RI bool `json:"prefer3RI,omitempty" yaml:"prefer3RI,omitempty"` + + PreferNetworkToken bool `json:"preferNetworkToken,omitempty" yaml:"preferNetworkToken,omitempty"` } From 17ad02cce357d69f61aa942e5a6e3a3bc260f68b Mon Sep 17 00:00:00 2001 From: Tom Kay Date: Fri, 30 Aug 2024 13:05:05 +0100 Subject: [PATCH 02/27] Recaptcha Fraud Connector (#207) * add Recaptcha policy * remove unused consts * rename to secretKey * set spec version to v1 * update field * update type * include clientKey * rename to SiteKey * fix tags * replace with fraud connector * add recaptcha to library register * add recaptcha to library validation * remove secret key as secure field, it's needed in assemble * remove required validation. allows omitting threshold (or setting it to zero) to permit all traffic --- connectorconfig/library.go | 8 +++++ connectorconfig/recaptcha.go | 68 ++++++++++++++++++++++++++++++++++++ v1/connector/connector.go | 2 +- 3 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 connectorconfig/recaptcha.go diff --git a/connectorconfig/library.go b/connectorconfig/library.go index 9c64891..fcce0ab 100644 --- a/connectorconfig/library.go +++ b/connectorconfig/library.go @@ -49,6 +49,7 @@ const ( LibraryMaxMind Library = "maxmind" LibraryCyberSource Library = "cybersource" LibraryKount Library = "kount" + LibraryRecaptcha Library = "recaptcha" // Updater Libraries LibraryPaySafeAccountUpdater Library = "paysafe-accountupdater" @@ -265,6 +266,13 @@ var LibraryRegister = map[Library]LibraryDef{ return methodType == chtype.PAYMENT_METHOD_TYPE_CARD }, }, + LibraryRecaptcha: { + DisplayName: "Recaptcha", + Credentials: func() Credentials { return &RecaptchaCredentials{} }, + SupportsMethod: func(methodType chtype.PaymentMethodType, methodProvider chtype.PaymentMethodProvider) bool { + return true + }, + }, LibraryClearhaus: { DisplayName: "Clearhaus", Credentials: func() Credentials { return &ClearhausCredentials{} }, diff --git a/connectorconfig/recaptcha.go b/connectorconfig/recaptcha.go new file mode 100644 index 0000000..84c2577 --- /dev/null +++ b/connectorconfig/recaptcha.go @@ -0,0 +1,68 @@ +package connectorconfig + +import ( + "encoding/json" + + "github.com/chargehive/configuration/environment" + "github.com/chargehive/configuration/v1/connector" + "github.com/chargehive/proto/golang/chargehive/chtype" +) + +type RecaptchaCredentials struct { + SiteKey string `json:"siteKey" yaml:"siteKey" validate:"required"` + SecretKey string `json:"secretKey" yaml:"secretKey" validate:"required"` + BlockThreshold float32 `json:"blockThreshold" yaml:"blockThreshold" validate:"min=0,max=1"` +} + +func (c *RecaptchaCredentials) GetLibrary() Library { + return LibraryRecaptcha +} + +func (c *RecaptchaCredentials) GetSupportedTypes() []LibraryType { + return []LibraryType{LibraryTypeFraud} +} + +func (c *RecaptchaCredentials) Validate() error { + return nil +} + +func (c *RecaptchaCredentials) GetSecureFields() []*string { + return []*string{} +} + +func (c *RecaptchaCredentials) ToConnector() connector.Connector { + con := connector.Connector{Library: string(c.GetLibrary())} + con.Configuration, _ = json.Marshal(c) + return con +} + +func (c *RecaptchaCredentials) FromJson(input []byte) error { + return json.Unmarshal(input, c) +} + +func (c *RecaptchaCredentials) SupportsSca() bool { + return true +} + +func (c *RecaptchaCredentials) SupportsMethod(methodType chtype.PaymentMethodType, methodProvider chtype.PaymentMethodProvider) bool { + if !c.GetLibrary().SupportsMethod(methodType, methodProvider) { + return false + } + return true +} + +func (c *RecaptchaCredentials) SupportsCountry(country string) bool { + return true +} + +func (c *RecaptchaCredentials) CanPlanModeUse(mode environment.Mode) bool { + return true +} + +func (c *RecaptchaCredentials) IsRecoveryAgent() bool { + return false +} + +func (c *RecaptchaCredentials) Supports3RI() bool { + return false +} diff --git a/v1/connector/connector.go b/v1/connector/connector.go index 7ac958c..28b53f7 100644 --- a/v1/connector/connector.go +++ b/v1/connector/connector.go @@ -25,7 +25,7 @@ const ( // Connector is a configuration file for a single payment processing entity type Connector struct { ProcessingState ProcessingState `json:"processingState,omitempty" yaml:"processingState,omitempty"` - Library string `json:"library" yaml:"library" validate:"omitempty,oneof=flexpay adyen bluesnap gpayments nuvei inoviopay threedsecureio sandbox sandbanx applepay authorize braintree qualpay stripe paysafe worldpay paypal-websitepaymentspro paypal-expresscheckout vindicia maxmind cybersource paysafe-accountupdater bottomline checkout kount clearhaus trust-payments cwams yapstone tokenex-accountupdater tokenex-networktokenization sticky-io googlepay"` + Library string `json:"library" yaml:"library" validate:"omitempty,oneof=recaptcha flexpay adyen bluesnap gpayments nuvei inoviopay threedsecureio sandbox sandbanx applepay authorize braintree qualpay stripe paysafe worldpay paypal-websitepaymentspro paypal-expresscheckout vindicia maxmind cybersource paysafe-accountupdater bottomline checkout kount clearhaus trust-payments cwams yapstone tokenex-accountupdater tokenex-networktokenization sticky-io googlepay"` Configuration []byte `json:"configuration" yaml:"configuration" validate:"required"` ConfigID string `json:"configId,omitempty" yaml:"configId,omitempty"` ConfigAuth string `json:"configAuth,omitempty" yaml:"configAuth,omitempty"` From e57962671b30ee71a04dd2c39fdd5d368764f116 Mon Sep 17 00:00:00 2001 From: Tom Kay Date: Wed, 4 Sep 2024 08:57:13 +0100 Subject: [PATCH 03/27] Recaptcha Enterprise (#208) * replace with apiKey for enterprise * projectid * block threshold is no longer used --- connectorconfig/recaptcha.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/connectorconfig/recaptcha.go b/connectorconfig/recaptcha.go index 84c2577..1a35fbf 100644 --- a/connectorconfig/recaptcha.go +++ b/connectorconfig/recaptcha.go @@ -9,9 +9,8 @@ import ( ) type RecaptchaCredentials struct { - SiteKey string `json:"siteKey" yaml:"siteKey" validate:"required"` - SecretKey string `json:"secretKey" yaml:"secretKey" validate:"required"` - BlockThreshold float32 `json:"blockThreshold" yaml:"blockThreshold" validate:"min=0,max=1"` + SiteKey string `json:"siteKey" yaml:"siteKey" validate:"required"` + ProjectID string `json:"projectId" yaml:"projectId" validate:"required"` } func (c *RecaptchaCredentials) GetLibrary() Library { From faa25e191b58088154a0362f0170bb39088c72e4 Mon Sep 17 00:00:00 2001 From: Okechukwu Ugwu Date: Thu, 5 Sep 2024 13:27:35 +0100 Subject: [PATCH 04/27] Allow users to specify recovery agent in attempt config (#209) --- v1/scheduler/attempt_config.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/v1/scheduler/attempt_config.go b/v1/scheduler/attempt_config.go index 3e103a6..f59682b 100644 --- a/v1/scheduler/attempt_config.go +++ b/v1/scheduler/attempt_config.go @@ -28,4 +28,6 @@ type AttemptConfig struct { Prefer3RI bool `json:"prefer3RI,omitempty" yaml:"prefer3RI,omitempty"` PreferNetworkToken bool `json:"preferNetworkToken,omitempty" yaml:"preferNetworkToken,omitempty"` + + RecoveryAgentConnectorID string `json:"recoveryAgentConnectorID" yaml:"recoveryAgentConnectorID"` } From 2186100ba5d4458b3de7c4bdb08613555ccc34d8 Mon Sep 17 00:00:00 2001 From: Tom Kay Date: Thu, 5 Sep 2024 17:06:59 +0100 Subject: [PATCH 05/27] Recaptcha Suggestions (#210) * add suggestion configuration to recaptcha * update action key * mod update * update go --- .github/workflows/unit-tests.yml | 6 +++--- connectorconfig/recaptcha.go | 11 +++++++++-- go.mod | 16 ++++++++-------- go.sum | 28 ++++++++++++++-------------- 4 files changed, 34 insertions(+), 27 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 09bfcd0..3ea168f 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -12,12 +12,12 @@ jobs: env: TEST_ENV: github steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: - go-version: 1.19 + go-version: "1.22" - name: Build run: | diff --git a/connectorconfig/recaptcha.go b/connectorconfig/recaptcha.go index 1a35fbf..32276da 100644 --- a/connectorconfig/recaptcha.go +++ b/connectorconfig/recaptcha.go @@ -8,9 +8,16 @@ import ( "github.com/chargehive/proto/golang/chargehive/chtype" ) +type RecaptchaSuggestionRange struct { + Min float32 `json:"min" yaml:"min" validate:"required"` + Max float32 `json:"max" yaml:"max" validate:"required"` + Action string `json:"action" yaml:"action" validate:"required, oneof=review allow deny"` +} + type RecaptchaCredentials struct { - SiteKey string `json:"siteKey" yaml:"siteKey" validate:"required"` - ProjectID string `json:"projectId" yaml:"projectId" validate:"required"` + SiteKey string `json:"siteKey" yaml:"siteKey" validate:"required"` + ProjectID string `json:"projectId" yaml:"projectId" validate:"required"` + Suggestions []RecaptchaSuggestionRange `json:"suggestions" yaml:"suggestions"` } func (c *RecaptchaCredentials) GetLibrary() Library { diff --git a/go.mod b/go.mod index 9ce65e1..0fd4e8a 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,9 @@ module github.com/chargehive/configuration -go 1.21 +go 1.22 require ( - github.com/chargehive/proto v1.12.0 + github.com/chargehive/proto v1.13.0 github.com/go-playground/assert/v2 v2.2.0 github.com/go-playground/locales v0.14.1 github.com/go-playground/universal-translator v0.18.1 @@ -15,13 +15,13 @@ replace github.com/go-playground/validator/v10 => github.com/go-playground/valid require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/gabriel-vasile/mimetype v1.4.5 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - golang.org/x/crypto v0.21.0 // indirect - golang.org/x/net v0.22.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect - google.golang.org/protobuf v1.33.0 // indirect + golang.org/x/crypto v0.26.0 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.18.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect ) diff --git a/go.sum b/go.sum index 00ed77f..5fedb94 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ -github.com/chargehive/proto v1.12.0 h1:MWTIDjcNQp7JRWxEYnlEpwyMN1xsmXGjIKgU79kTDpo= -github.com/chargehive/proto v1.12.0/go.mod h1:TSxF4AoWlaa2uwtEk3v+TC/jnKua1tk56m7Zi+85Dn0= +github.com/chargehive/proto v1.13.0 h1:0QnW/lwSZesV7f8ArVyHvnEocMAAsh6+of4kkjeb0RY= +github.com/chargehive/proto v1.13.0/go.mod h1:TSxF4AoWlaa2uwtEk3v+TC/jnKua1tk56m7Zi+85Dn0= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= -github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= +github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= @@ -20,15 +20,15 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 29feb1b3797482ac949e7d5b2f2a87b4e998de40 Mon Sep 17 00:00:00 2001 From: Tom Kay Date: Mon, 30 Sep 2024 17:00:28 +0100 Subject: [PATCH 06/27] set correct library type for gpayments (#211) --- connectorconfig/gpayments.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connectorconfig/gpayments.go b/connectorconfig/gpayments.go index 000a3f4..ba2e61d 100644 --- a/connectorconfig/gpayments.go +++ b/connectorconfig/gpayments.go @@ -33,7 +33,7 @@ func (c *GPaymentsCredentials) GetLibrary() Library { } func (c *GPaymentsCredentials) GetSupportedTypes() []LibraryType { - return []LibraryType{LibraryTypePayment} + return []LibraryType{LibraryTypeAuthentication} } func (c *GPaymentsCredentials) Validate() error { From 6f5395d1c4aa7ad84adf1631989a3791c92a1777 Mon Sep 17 00:00:00 2001 From: Brooke Bryan Date: Mon, 7 Oct 2024 17:04:57 +0100 Subject: [PATCH 07/27] Day of Week / Month support (#212) * Day of Week / Month support * Allow zero values * Add docs * Add docs * Add docs * Add docs --- docs/scheduler/sequential.md | 128 ++++++++++++++++++++++++----------- v1/scheduler/schedule.go | 6 ++ 2 files changed, 96 insertions(+), 38 deletions(-) diff --git a/docs/scheduler/sequential.md b/docs/scheduler/sequential.md index 1d2dadb..979e23f 100644 --- a/docs/scheduler/sequential.md +++ b/docs/scheduler/sequential.md @@ -1,39 +1,63 @@ # Sequential Scheduler -The sequential scheduler allows for a sequence or schedule of connectors to be used when attempting to complete a charge. +The sequential scheduler allows for a sequence or schedule of connectors to be used when attempting to complete a charge. They are mapped by attempt number. ## Format + As with all configs, the standard wrapper is used. ```json5 { - "kind": "SchedulerSequential", // Must be set to "SchedulerSequential" + "kind": "SchedulerSequential", + // Must be set to "SchedulerSequential" "metadata": { - "projectId": "test-project", // Must be set to the ChargeHive Project ID you were issued with - "name": "test-scheduler" // Set this to a memorable name for the method lock policy, no spaces, all lowercase + "projectId": "test-project", + // Must be set to the ChargeHive Project ID you were issued with + "name": "test-scheduler" + // Set this to a memorable name for the method lock policy, no spaces, all lowercase }, - "specVersion": "v1", // Must be set to the correct version - "selector": {}, // May be used to apply this to a subset of charges + "specVersion": "v1", + // Must be set to the correct version + "selector": {}, + // May be used to apply this to a subset of charges "spec": { - "schedules": { // Schedule object with the sequence of operation + "schedules": { + // Schedule object with the sequence of operation "0": { - "attemptConfig": { // Configuration used when processing this schedule - "poolType": "single", // The order that this attempt should iterate connectors - "methodSelector": "primary", // How payment method should be selected for this attempt - "connectorLimit": 0, // Maximum number of connectors to process within an attempt per method - "methodLimit": 0, // Maximum number of methods to be attempt per method - "cascadeDelay": null, // Delay between connector cascades - "overridePoolConnectorIDs": [ // Overrides the pool, and selects these connectors + "attemptConfig": { + // Configuration used when processing this schedule + "poolType": "single", + // The order that this attempt should iterate connectors + "methodSelector": "primary", + // How payment method should be selected for this attempt + "connectorLimit": 0, + // Maximum number of connectors to process within an attempt per method + "methodLimit": 0, + // Maximum number of methods to be attempt per method + "cascadeDelay": null, + // Delay between connector cascades + "overridePoolConnectorIDs": [ + // Overrides the pool, and selects these connectors "test-connector" ] - }, - "timeDelay": 86400000000000, // Delay in nanoseconds before the next Attempt - if set to 0, ChargeHive will still delay 30 minutes to avoid multiple attempts at the same time - "timeDelayOrigin": "initialisation", // Defines when the Delay before the next Attempt is based from - either "initialisation" or "last-failure" - "timeDelaySync": "Closest", // Specifies when the transaction should be performed relative to the schedules TimeSync - "timeWindowHours": "2", // Specifies the available duration for the transaction to be queued within - "timeSyncHour": 2, // An hour designation - "timeSyncZone": "UTC" // UTC or ULT + }, + "timeDelay": 86400000000000, + // Delay in nanoseconds before the next Attempt - if set to 0, ChargeHive will still delay 30 minutes to avoid multiple attempts at the same time + "timeDelayOrigin": "initialisation", + // Defines when the Delay before the next Attempt is based from - either "initialisation" or "last-failure" + "timeDelaySync": "Closest", + // Specifies when the transaction should be performed relative to the schedules TimeSync + "timeWindowHours": "2", + // Specifies the available duration for the transaction to be queued within + "timeSyncHour": 2, + // An hour designation + "timeSyncZone": "UTC", + // UTC or ULT + "dayOfMonth": 1, + // Day of the month to run, e.g. 1st + "dayOfWeek": 2 + // Day of the week to run, e.g. Tuesday (Monday = 1, Sunday = 7) }, } } @@ -41,16 +65,21 @@ As with all configs, the standard wrapper is used. ``` ### Schedule Definition + FieldName | Required | Definition ----:|---|:--- -[attemptConfig](#attemptconfig-definition)|true|Configuration to use when processing this schedule -timeDelay|true|Amount of time to wait before processing after TimeDelayOrigin in **nanoseconds** -[timeDelayOrigin](#timedelayorigin-values)|true|Specifies when the time origin is based from -[timeDelaySync](#timedelaysync-values)|true|Specifies when the transaction should be performed relative to the schedules TimeSync -timeSyncHour|true|An hour designation (0-23) i.e 2 == 2AM. Ignored if TimeDelaySync is set to None -[timeSyncZone](#timesynczone-values)|true|Indicates the timezone that the TimeSyncHour is relative to. Ignored if TimeDelaySync is set to None +---:|----------|:--- +[attemptConfig](#attemptconfig-definition)| true |Configuration to use when processing this schedule +timeDelay| true |Amount of time to wait before processing after TimeDelayOrigin in **nanoseconds** +[timeDelayOrigin](#timedelayorigin-values)| true |Specifies when the time origin is based from +[timeDelaySync](#timedelaysync-values)| true |Specifies when the transaction should be performed relative to the schedules TimeSync +timeWindowHours| false |Specifies the available duration for the transaction to be queued within +timeSyncHour| true |An hour designation (0-23) i.e 2 == 2AM. Ignored if TimeDelaySync is set to None +[timeSyncZone](#timesynczone-values)| true |Indicates the timezone that the TimeSyncHour is relative to. Ignored if TimeDelaySync is set to None +dayOfMonth| false |Day of the month to run (1-28) +dayOfWeek| false |Day of the week to run (1-7) (Monday = 1, Sunday = 7) ### AttemptConfig Definition + FieldName | Required | Definition ---:|---|:--- [poolType](#pooltype-values)|true|The order that this attempt should iterate connectors @@ -61,6 +90,7 @@ cascadeDelay|true|Duration to wait between each cascade in **nanoseconds** or nu overridePoolConnectorIDs|false|will use this connectors instead of the ones in the pool ### PoolType Values + Value | Definition ---:|:--- "single"|Provides a pool of a single connector @@ -68,6 +98,7 @@ Value | Definition "cascade"|Iterate connectors according to cascade rules ### MethodSelector Values + Value | Definition ---:|:--- "primary"|Indicates that the first available payment method should be used @@ -76,24 +107,45 @@ Value | Definition "all-backup"| Indicates that anything available other than the 1st (primary) should be used ### TimeDelayOrigin Values + Value| Definition ---:|:--- "initialisation"|Indicates that the time is based from the initialisation of the charge "last-failure"|Indicates that the time is based from the last transaction failure ### TimeDelaySync Values -Value| Definition ----:|:--- -"None"|will ignore the TimeSyncHour value -"Earliest"|will run the transaction at the earliest sync hour relative to TimeSync -"Latest"|will run the transaction at the latest sync hour relative to TimeSync -"Closest"|will run the transaction at the closest sync hour relative to TimeSync + +Value | Definition +-----------:|:-------------------------- +"None" |will ignore the TimeSyncHour value +"Earliest" |will run the transaction at the earliest sync hour relative to TimeSync +"Latest" |will run the transaction at the latest sync hour relative to TimeSync +"Closest" |will run the transaction at the closest sync hour relative to TimeSync ### TimeSyncZone Values -Value| Definition ----:|:--- -"ULT"|Users Local Time -"UTC"|Universal Time Coordinated + + Value | Definition +------:|:--------------------------- + "ULT" | Users Local Time + "UTC" | Universal Time Coordinated + +### Day Of Month + + Value | Definition +------:|:------------------------ + 1-28 | Day of the month to run + +### Day Of Week + + Value | Definition +------:|:----------- +1 | Monday +2 | Tuesday +3 | Wednesday +4 | Thursday +5 | Friday +6 | Saturday +7 | Sunday ## Full Example diff --git a/v1/scheduler/schedule.go b/v1/scheduler/schedule.go index 528acd2..3fe29de 100644 --- a/v1/scheduler/schedule.go +++ b/v1/scheduler/schedule.go @@ -24,4 +24,10 @@ type Schedule struct { // TimeSyncZone indicates the timezone that the TimeSyncHour is relative to. Ignored if TimeDelaySync is set to None TimeSyncZone TimeZone `json:"timeSyncZone" yaml:"timeSyncZone" validate:"oneof=ULT UTC CIT"` + + // DayOfMonth is the day of the month to process the schedule + DayOfMonth int `json:"dayOfMonth" yaml:"dayOfMonth" validate:"min=0,max=28"` + + // DayOfWeek is the day of the week to process the schedule (1 = Monday) - Sunday moved to 7 to leave 0 as an ignored value + DayOfWeek int `json:"dayOfWeek" yaml:"dayOfWeek" validate:"min=0,max=7"` } From cda2f4ac1ac425dd2d2818c09a3a2583bc8e95e1 Mon Sep 17 00:00:00 2001 From: Brooke Bryan Date: Tue, 8 Oct 2024 14:27:54 +0100 Subject: [PATCH 08/27] Updated schedule options (#213) --- v1/scheduler/enums.go | 23 +++++++++++++++++++++++ v1/scheduler/schedule.go | 39 ++++++++++++++++++++++++++------------- 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/v1/scheduler/enums.go b/v1/scheduler/enums.go index 0c78702..7dc11a2 100644 --- a/v1/scheduler/enums.go +++ b/v1/scheduler/enums.go @@ -131,3 +131,26 @@ const ( // TimeZoneCIT Charge Initialisation Time (Midnight = Charge Time) TimeZoneCIT TimeZone = "CIT" ) + +type DayType string + +const ( + // DayTypeNone indicates no specific day type + DayTypeNone DayType = "" + // DayTypeWeekday indicates a weekday Monday to Friday + DayTypeWeekday DayType = "weekday" + // DayTypeWeekend indicates a weekend day Saturday or Sunday + DayTypeWeekend DayType = "weekend" +) + +type DayShift string + +const ( + DayShiftNone DayShift = "" + // DayShiftForward move the date forward to match the day + DayShiftForward DayShift = "forward" + // DayShiftBackward move the date backward to match the day + DayShiftBackward DayShift = "backward" + // DayShiftClosest move the date to the closest day + DayShiftClosest DayShift = "closest" +) diff --git a/v1/scheduler/schedule.go b/v1/scheduler/schedule.go index 3fe29de..86fac39 100644 --- a/v1/scheduler/schedule.go +++ b/v1/scheduler/schedule.go @@ -7,27 +7,40 @@ type Schedule struct { // AttemptConfig is the configuration to use when processing this schedule AttemptConfig AttemptConfig `json:"attemptConfig" yaml:"attemptConfig" validate:"required,dive"` - // TimeDelay is the amount of time to wait before processing after TimeDelayOrigin - TimeDelay time.Duration `json:"timeDelay" yaml:"timeDelay" validate:"gte=0"` + // TimeDelay [deprecated - prefer delay days] is the amount of time to wait before processing after TimeDelayOrigin + TimeDelay time.Duration `json:"timeDelay,omitempty" yaml:"timeDelay" validate:"gte=0"` + + // DAY CONFIG + + // DelayDays is the number of days to delay the schedule by + DelayDays int `json:"delayDays,omitempty" yaml:"delayDays" validate:"gte=0"` + + // DayOfMonth is the day of the month to process the schedule + DayOfMonth int `json:"dayOfMonth,omitempty" yaml:"dayOfMonth" validate:"min=0,max=28"` + + // DayOfWeek is the day of the week to process the schedule (1 = Monday) - Sunday moved to 7 to leave 0 as an ignored value + DayOfWeek int `json:"dayOfWeek,omitempty" yaml:"dayOfWeek" validate:"min=0,max=7"` + + // DayType indicates the type of day to process the schedule + DayType DayType `json:"dayType,omitempty" yaml:"dayType" validate:"oneof='' weekday weekend"` + + // DayShift indicates the direction to take when syncing to Days + DayShift DayShift `json:"daySync,omitempty" yaml:"daySync" validate:"oneof='' forward backward"` + + // TIME CONFIG // TimeDelayOrigin specifies when the time origin is based from - TimeDelayOrigin AttemptOriginType `json:"timeDelayOrigin" yaml:"timeDelayOrigin" validate:"oneof=initialisation last-failure"` + TimeDelayOrigin AttemptOriginType `json:"timeDelayOrigin,omitempty" yaml:"timeDelayOrigin" validate:"oneof=initialisation last-failure"` // TimeDelaySync indicates the direction in time that the schedule should move when syncing to TimeSyncHour - TimeDelaySync TimeDelaySync `json:"timeDelaySync" yaml:"timeDelaySync" validate:"oneof=None Earliest Latest Closest"` + TimeDelaySync TimeDelaySync `json:"timeDelaySync,omitempty" yaml:"timeDelaySync" validate:"oneof=None Earliest Latest Closest"` // TimeSyncHour is an hour designation (0-23) i.e 2 == 2AM. Ignored if TimeDelaySync is set to None - TimeSyncHour int `json:"timeSyncHour" yaml:"timeSyncHour" validate:"min=0,max=23"` + TimeSyncHour int `json:"timeSyncHour,omitempty" yaml:"timeSyncHour" validate:"min=0,max=23"` // TimeWindowHours is the number of hours grace for a transaction to be processed within. Allowing for a transaction to be processed within X hours of the requested delay & sync hour e.g. 10am > 11am with a TimeWindowHours of 1 - TimeWindowHours int `json:"timeWindowHours" yaml:"timeWindowHours" validate:"gte=0"` + TimeWindowHours int `json:"timeWindowHours,omitempty" yaml:"timeWindowHours" validate:"gte=0"` // TimeSyncZone indicates the timezone that the TimeSyncHour is relative to. Ignored if TimeDelaySync is set to None - TimeSyncZone TimeZone `json:"timeSyncZone" yaml:"timeSyncZone" validate:"oneof=ULT UTC CIT"` - - // DayOfMonth is the day of the month to process the schedule - DayOfMonth int `json:"dayOfMonth" yaml:"dayOfMonth" validate:"min=0,max=28"` - - // DayOfWeek is the day of the week to process the schedule (1 = Monday) - Sunday moved to 7 to leave 0 as an ignored value - DayOfWeek int `json:"dayOfWeek" yaml:"dayOfWeek" validate:"min=0,max=7"` + TimeSyncZone TimeZone `json:"timeSyncZone,omitempty" yaml:"timeSyncZone" validate:"oneof=ULT UTC CIT"` } From a2140afe5dc0e9d3129f7ab73f50461a13cb2a71 Mon Sep 17 00:00:00 2001 From: Brooke Bryan Date: Fri, 11 Oct 2024 09:51:47 +0100 Subject: [PATCH 09/27] Support up to 31 days for dayOfMonth (#214) --- docs/scheduler/sequential.md | 2 +- v1/scheduler/schedule.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/scheduler/sequential.md b/docs/scheduler/sequential.md index 979e23f..2d3d969 100644 --- a/docs/scheduler/sequential.md +++ b/docs/scheduler/sequential.md @@ -75,7 +75,7 @@ timeDelay| true |Amount of time to wait before processing after TimeDelayOri timeWindowHours| false |Specifies the available duration for the transaction to be queued within timeSyncHour| true |An hour designation (0-23) i.e 2 == 2AM. Ignored if TimeDelaySync is set to None [timeSyncZone](#timesynczone-values)| true |Indicates the timezone that the TimeSyncHour is relative to. Ignored if TimeDelaySync is set to None -dayOfMonth| false |Day of the month to run (1-28) +dayOfMonth| false |Day of the month to run (1-31) dayOfWeek| false |Day of the week to run (1-7) (Monday = 1, Sunday = 7) ### AttemptConfig Definition diff --git a/v1/scheduler/schedule.go b/v1/scheduler/schedule.go index 86fac39..e9257c1 100644 --- a/v1/scheduler/schedule.go +++ b/v1/scheduler/schedule.go @@ -16,7 +16,7 @@ type Schedule struct { DelayDays int `json:"delayDays,omitempty" yaml:"delayDays" validate:"gte=0"` // DayOfMonth is the day of the month to process the schedule - DayOfMonth int `json:"dayOfMonth,omitempty" yaml:"dayOfMonth" validate:"min=0,max=28"` + DayOfMonth int `json:"dayOfMonth,omitempty" yaml:"dayOfMonth" validate:"min=0,max=31"` // DayOfWeek is the day of the week to process the schedule (1 = Monday) - Sunday moved to 7 to leave 0 as an ignored value DayOfWeek int `json:"dayOfWeek,omitempty" yaml:"dayOfWeek" validate:"min=0,max=7"` From bf99bb5a849c4908ad1776622c478054ef4a8810 Mon Sep 17 00:00:00 2001 From: Brooke Bryan Date: Fri, 11 Oct 2024 11:20:41 +0100 Subject: [PATCH 10/27] Add BPID bucket (#215) --- selector/key.go | 1 + 1 file changed, 1 insertion(+) diff --git a/selector/key.go b/selector/key.go index 06ea316..4663116 100644 --- a/selector/key.go +++ b/selector/key.go @@ -5,6 +5,7 @@ type Key string const ( KeyNow Key = "now" KeyRandomPercent Key = "randompercent" + KeyBucketBPID Key = "bucket.bpid" ) const ( // Assemble Properties From 499ac4a1bdd36053eb71574e7471592742d8c202 Mon Sep 17 00:00:00 2001 From: Brooke Bryan Date: Mon, 14 Oct 2024 11:23:18 +0100 Subject: [PATCH 11/27] Connector retry type (#216) --- v1/scheduler/attempt_config.go | 3 +++ v1/scheduler/enums.go | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/v1/scheduler/attempt_config.go b/v1/scheduler/attempt_config.go index f59682b..152287f 100644 --- a/v1/scheduler/attempt_config.go +++ b/v1/scheduler/attempt_config.go @@ -10,6 +10,9 @@ type AttemptConfig struct { // MethodSelector indicates how payment method should be selected for this attempt MethodSelector MethodSelector `json:"methodSelector" yaml:"methodSelector" validate:"oneof=primary backup all all-backup"` + // ConnectorRetryType indicates how the attempt should retry (on the same connector), if needed + ConnectorRetryType ConnectorRetryType `json:"connectorRetryType" yaml:"connectorRetryType" validate:"oneof='' token-pan pan-token"` + // ConnectorLimit is a maximum number of connectors to process within an attempt per method ConnectorLimit int32 `json:"connectorLimit" yaml:"connectorLimit" validate:"min=0,max=1000"` diff --git a/v1/scheduler/enums.go b/v1/scheduler/enums.go index 7dc11a2..c9d168e 100644 --- a/v1/scheduler/enums.go +++ b/v1/scheduler/enums.go @@ -154,3 +154,14 @@ const ( // DayShiftClosest move the date to the closest day DayShiftClosest DayShift = "closest" ) + +type ConnectorRetryType string + +const ( + // ConnectorRetryTypeNone No retry + ConnectorRetryTypeNone ConnectorRetryType = "" + // ConnectorRetryTypeTokenToPan Use the token first, cascade to Pan if available + ConnectorRetryTypeTokenToPan ConnectorRetryType = "token-pan" + // ConnectorRetryTypePanToToken Use the Pan first, cascade to Token if available + ConnectorRetryTypePanToToken ConnectorRetryType = "pan-token" +) From abfc639cbe434441292cb412b460fffe40b5e729 Mon Sep 17 00:00:00 2001 From: Brooke Bryan Date: Fri, 18 Oct 2024 17:40:45 +0100 Subject: [PATCH 12/27] Added charge policy (#217) --- utils/generate.go | 4 +++ v1/policy/charge.go | 82 +++++++++++++++++++++++++++++++++++++++++++++ v1/policy/init.go | 9 +++++ 3 files changed, 95 insertions(+) create mode 100644 v1/policy/charge.go diff --git a/utils/generate.go b/utils/generate.go index af04d80..ab7ca36 100644 --- a/utils/generate.go +++ b/utils/generate.go @@ -53,6 +53,7 @@ const ( // policy confPolCascade Template = "pol_cascade" confPolChargeExpiry Template = "pol_chargeExpiry" + confPolCharge Template = "pol_charge" confPolFraud Template = "pol_fraud" confPolMethodLock Template = "pol_methodLock" confPolMethodUpgrade Template = "pol_methodUpgrade" @@ -92,6 +93,7 @@ var Templates = map[Template]string{ confConnFlexPay: "Connector: FlexPay", confIntSlack: "Integration: Slack", confPolCascade: "Policy: Cascade", + confPolCharge: "Policy: Charge", confPolChargeExpiry: "Policy: Charge Expiry", confPolFraud: "Policy: Fraud", confPolMethodLock: "Policy: Method Lock", @@ -350,6 +352,8 @@ func buildSpec(conf Template) (object.Specification, error) { return policy.CascadePolicy{Rules: []policy.CascadeRule{{Library: connectorconfig.Library(chg), OriginalResponseCode: chg}}}, nil case confPolChargeExpiry: return policy.ChargeExpiryPolicy{}, nil + case confPolCharge: + return policy.ChargePolicy{}, nil case confPolFraud: return policy.FraudPolicy{ConnectorIDs: []string{chg}, CheckTime: "preauth-first", CheckType: "all"}, nil case confPolMethodLock: diff --git a/v1/policy/charge.go b/v1/policy/charge.go new file mode 100644 index 0000000..481e83f --- /dev/null +++ b/v1/policy/charge.go @@ -0,0 +1,82 @@ +package policy + +import ( + "encoding/json" + "errors" + "github.com/chargehive/configuration/object" +) + +// KindPolicyCharge is the identifier for a PolicyCharge config +const KindPolicyCharge object.Kind = "PolicyCharge" + +// Restriction is the type of API involvement +type Restriction string + +const ( + // RestrictionNone requires no api involvement + RestrictionNone Restriction = "" + + // RestrictionAPIInitiate requires the api to initiate the request + RestrictionAPIInitiate Restriction = "api-initiate" + + // RestrictionAPIVerify requires the api to be involved before proceeding + RestrictionAPIVerify Restriction = "api-verify" + + // RestrictionBlock should block the request + RestrictionBlock Restriction = "block" +) + +// ChargePolicy defines the constraints that when exceeded a charge will not expire +type ChargePolicy struct { + // MaxAuthAttempts is the number of auths that can be processed, 0 for unlimited + MaxAuthAttempts int64 `json:"authAttempts" yaml:"authAttempts" validate:"min=0"` + + // AmountUpperLimit is the maximum amount that can be processed + AmountUpperLimit int64 `json:"amountUpperLimit" yaml:"amountUpperLimit" validate:"min=0"` + + // AmountLowerLimit is the minimum amount that can be processed + AmountLowerLimit int64 `json:"amountLowerLimit" yaml:"amountLowerLimit" validate:"min=0"` + + // AllowAmounts is a list of amounts that are allowed to be processed + AllowAmounts []int64 `json:"allowAmounts" yaml:"allowAmounts"` + + // OnCreation is the restriction on charge creation + OnCreation Restriction `json:"onCreation" yaml:"onCreation" validate:"omitempty,oneof='' api-initiate api-verify block"` + + // OnAuth is the restriction on charge auth + OnAuth Restriction `json:"onAuth" yaml:"onAuth" validate:"omitempty,oneof='' api-initiate api-verify block"` + + // OnCapture is the restriction on charge capture + OnCapture Restriction `json:"onCapture" yaml:"onCapture" validate:"omitempty,oneof='' api-initiate api-verify block"` + + // OnRefund is the restriction on charge refund + OnRefund Restriction `json:"onRefund" yaml:"onRefund" validate:"omitempty,oneof='' api-initiate api-verify block"` +} + +// GetKind returns the ChargePolicy kind +func (ChargePolicy) GetKind() object.Kind { return KindPolicyCharge } + +// GetVersion returns the ChargePolicy version +func (ChargePolicy) GetVersion() string { return "v1" } + +// ChargePolicyDefinition is the Charge config object definition +type ChargePolicyDefinition struct{ def *object.Definition } + +// NewChargePolicyDefinition creates a new ChargePolicyDefinition +func NewChargePolicyDefinition(d *object.Definition) (*ChargePolicyDefinition, error) { + if _, ok := d.Spec.(*ChargePolicy); ok { + return &ChargePolicyDefinition{def: d}, nil + } + return nil, errors.New("invalid Charge policy object") +} + +// Definition returns the ChargePolicyDefinition structure +func (d *ChargePolicyDefinition) Definition() *object.Definition { return d.def } + +// MarshalJSON returns the JSON value for the ChargePolicyDefinition +func (d *ChargePolicyDefinition) MarshalJSON() ([]byte, error) { return json.Marshal(d.def) } + +// Spec returns the CascadePolicy contained within the ChargePolicyDefinition +func (d *ChargePolicyDefinition) Spec() *ChargePolicy { + return d.def.Spec.(*ChargePolicy) +} diff --git a/v1/policy/init.go b/v1/policy/init.go index 8de10a5..503343b 100644 --- a/v1/policy/init.go +++ b/v1/policy/init.go @@ -8,6 +8,7 @@ func GetHandlers() []object.KindHandler { funcs = append(funcs, scaPolicy()...) funcs = append(funcs, fraudPolicy()...) funcs = append(funcs, chargeExpiryPolicy()...) + funcs = append(funcs, chargePolicy()...) funcs = append(funcs, methodUpgradePolicy()...) funcs = append(funcs, cascadePolicy()...) funcs = append(funcs, methodLockPolicy()...) @@ -40,6 +41,14 @@ func chargeExpiryPolicy() []object.KindHandler { } } +func chargePolicy() []object.KindHandler { + o := ChargePolicy{} + return []object.KindHandler{ + object.NewKindHandler(o.GetKind(), object.KindHandlerDefaultVersion, func() object.Specification { return &ChargePolicy{} }), + object.NewKindHandler(o.GetKind(), o.GetVersion(), func() object.Specification { return &ChargePolicy{} }), + } +} + func methodUpgradePolicy() []object.KindHandler { o := MethodUpgradePolicy{} return []object.KindHandler{ From e29a50bf7cae3ec8c27371e45e17734a74d76e7d Mon Sep 17 00:00:00 2001 From: Brooke Bryan Date: Mon, 21 Oct 2024 16:55:24 +0100 Subject: [PATCH 13/27] Register Bucket BPID key (#218) --- selector/key.go | 1 + 1 file changed, 1 insertion(+) diff --git a/selector/key.go b/selector/key.go index 4663116..0830606 100644 --- a/selector/key.go +++ b/selector/key.go @@ -180,6 +180,7 @@ const ( // Payment Method var KeyRegister = map[Key]bool{ KeyNow: true, KeyRandomPercent: true, + KeyBucketBPID: true, KeyChargeLabel: true, KeyChargeCurrentTransactionNumber: true, KeyChargeCurrentAttemptNumber: true, From 3580b98dab274862316ec92cf1ae3517965ad79b Mon Sep 17 00:00:00 2001 From: Brooke Bryan Date: Tue, 22 Oct 2024 10:41:42 +0100 Subject: [PATCH 14/27] Not Like Support (#219) --- selector/predicates.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/selector/predicates.go b/selector/predicates.go index 75ac7fc..281d43a 100644 --- a/selector/predicates.go +++ b/selector/predicates.go @@ -13,6 +13,8 @@ const ( PredicateOperatorLessThan PredicateOperator = "Lt" PredicateOperatorLike PredicateOperator = "Like" PredicateOperatorInLike PredicateOperator = "InLike" + PredicateOperatorNotLike PredicateOperator = "NotLike" + PredicateOperatorNotInLike PredicateOperator = "NotInLike" ) type OperatorConversion string From a71821874d7a5063b7ed084616543d3bdb9350f0 Mon Sep 17 00:00:00 2001 From: Brooke Bryan Date: Tue, 22 Oct 2024 11:55:58 +0100 Subject: [PATCH 15/27] Add kount custom data defaults (#220) --- connectorconfig/kount.go | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/connectorconfig/kount.go b/connectorconfig/kount.go index e54570c..8d1204a 100644 --- a/connectorconfig/kount.go +++ b/connectorconfig/kount.go @@ -15,14 +15,20 @@ const ( KountEnvironmentProduction KountEnvironment = "production" ) +type KountCustomData struct { + Key string `json:"key" yaml:"key" validate:"required"` + Value string `json:"value" yaml:"value"` +} + type KountCredentials struct { - SiteID string `json:"siteID" yaml:"siteID" validate:"required"` - MerchantID string `json:"merchantID" yaml:"merchantID" validate:"required"` - ConfigKey string `json:"configKey" yaml:"configKey" validate:"required"` - APIKey string `json:"apiKey" yaml:"apiKey" validate:"required"` - DataCollectorURL string `json:"dataCollectorURL" yaml:"dataCollectorURL" validate:"required"` - RiskInquiryServiceURL string `json:"riskInquiryServiceURL" yaml:"riskInquiryServiceURL" validate:"required"` - Environment KountEnvironment `json:"environment" yaml:"environment" validate:"oneof=test production"` + SiteID string `json:"siteID" yaml:"siteID" validate:"required"` + MerchantID string `json:"merchantID" yaml:"merchantID" validate:"required"` + ConfigKey string `json:"configKey" yaml:"configKey" validate:"required"` + APIKey string `json:"apiKey" yaml:"apiKey" validate:"required"` + DataCollectorURL string `json:"dataCollectorURL" yaml:"dataCollectorURL" validate:"required"` + RiskInquiryServiceURL string `json:"riskInquiryServiceURL" yaml:"riskInquiryServiceURL" validate:"required"` + Environment KountEnvironment `json:"environment" yaml:"environment" validate:"oneof=test production"` + DefaultCustomData []KountCustomData `json:"defaultCustomData" yaml:"defaultCustomData"` } func (c *KountCredentials) GetMID() string { From 3d1ca53b24137836274ef54f45fd99495a407583 Mon Sep 17 00:00:00 2001 From: Tom Kay Date: Fri, 25 Oct 2024 00:44:36 +0100 Subject: [PATCH 16/27] Google Pay billing format (#221) * add google billing address format * remove shipping address format (not a valid option for google pay) * mod update * fix tests --- connectorconfig/googlePay.go | 30 +++++++++++------------------ go.mod | 16 ++++++++-------- go.sum | 28 +++++++++++++-------------- utils/generate.go | 37 ++++++++++++++++++------------------ 4 files changed, 51 insertions(+), 60 deletions(-) diff --git a/connectorconfig/googlePay.go b/connectorconfig/googlePay.go index 75e507b..4363f1f 100644 --- a/connectorconfig/googlePay.go +++ b/connectorconfig/googlePay.go @@ -19,6 +19,7 @@ type GooglePayCredential interface { GetGoogleCardAllowPrepaid() bool GetGoogleCardAllowCredit() bool GetGoogleCardBillingAddressReq() bool + GetGoogleCardBillingAddressFormat() GoogleCardBillingAddressFormat GetGoogleCardBillingPhoneReq() bool GetGoogleCardShippingAddressReq() bool GetGoogleCardShippingPhoneReq() bool @@ -62,7 +63,7 @@ type GooglePayCredentials struct { // GoogleCardBillingPhoneReq (Card {parameters.billingAddressParameters.phoneNumberRequired) Set to true if a phone number is required to process the transaction. GoogleCardBillingPhoneReq bool `json:"googleCardBillingPhoneReq,omitempty" yaml:"googleCardBillingPhoneReq,omitempty" validate:"-"` // GoogleCardBillingAddressFormat (Card {parameters.billingAddressParameters.format) Billing address format required to complete the transaction. - GoogleCardBillingAddressFormat GoogleCardBillingAddressReq `json:"googleCardBillingAddressFormat,omitempty" yaml:"googleCardBillingAddressFormat,omitempty" validate:"required_with=GoogleMerchantId,omitempty,oneof=MIN FULL"` + GoogleCardBillingAddressFormat GoogleCardBillingAddressFormat `json:"googleCardBillingAddressFormat,omitempty" yaml:"googleCardBillingAddressFormat,omitempty" validate:"required_with=GoogleMerchantId,omitempty,oneof=MIN FULL"` // GoogleCardTokenType (Card {tokenizationSpecification.type}) GoogleCardTokenType GoogleTokenType `json:"googleCardTokenType,omitempty" yaml:"googleCardTokenType,omitempty" validate:"required_with=GoogleMerchantId,omitempty,oneof=DIRECT PAYMENT_GATEWAY"` // GoogleCardGateway (Card {tokenizationSpecification.parameters.gateway}) https://developers.google.com/pay/api/web/reference/request-objects#gateway @@ -74,8 +75,6 @@ type GooglePayCredentials struct { GoogleCardShippingAddressReq bool `json:"googleCardShippingAddressReq,omitempty" yaml:"googleCardShippingAddressReq,omitempty" validate:"-"` // GoogleCardShippingPhoneReq Set to true if a phone number is required to process the transaction. GoogleCardShippingPhoneReq bool `json:"googleCardShippingPhoneReq,omitempty" yaml:"googleCardShippingPhoneReq,omitempty" validate:"-"` - // GoogleCardShippingAddressFormat (Card {parameters.shippingAddressParameters.format) Shipping address format required to complete the transaction. - GoogleCardShippingAddressFormat GoogleCardBillingAddressReq `json:"googleCardShippingAddressFormat,omitempty" yaml:"googleCardShippingAddressFormat,omitempty" validate:"omitempty,oneof=MIN FULL"` // GoogleAcquirerCountry The ISO 3166-1 alpha-2 country code where the transaction is processed. This property is required for merchants who process transactions in European Economic Area (EEA) countries and any other countries that are subject to Strong Customer Authentication (SCA). Merchants must specify the acquirer bank country code. GoogleAcquirerCountry string `json:"googleAcquirerCountry,omitempty" yaml:"googleAcquirerCountry,omitempty" validate:"omitempty,oneof=AF AX AL DZ AS AD AO AI AQ AG AR AM AW AU AT AZ BS BH BD BB BY BE BZ BJ BM BT BO BQ BA BW BV BR IO BN BG BF BI KH CM CA CV KY CF TD CL CN CX CC CO KM CG CD CK CR CI HR CU CW CY CZ DK DJ DM DO EC EG SV GQ ER EE ET FK FO FJ FI FR GF PF TF GA GM GE DE GH GI GR GL GD GP GU GT GG GN GW GY HT HM HN HK HU IS IN ID IR IQ IE IM IL IT JM JP JE JO KZ KE KI KP KR KW KG LA LV LB LS LR LY LI LT LU MO MK MG MW MY MV ML MT MH MQ MR MU YT MX FM MD MC MN ME MS MA MZ MM NA NR NP NC NZ NI NE NG NU NF MP NO OM PK PW PS PA PG PY PE PH PN PL PT PR QA RE RO RU RW BL SH KN LC MF VC WS SM ST SA SN RS SC SL SG SX SK SI SB SO ZA GS SS ES LK PM SD SR SJ SZ SE CH SY TW TJ TZ TH NL TL TG TK TO TT TN TR TM TC TV UG UA AE GB US UM UY UZ VU VA VE VN VG VI WF EH YE ZM ZW"` @@ -237,7 +236,7 @@ func (g *GooglePayCredentials) GetGoogleCardBillingAddressReq() bool { } return g.GoogleCardBillingAddressReq } -func (g *GooglePayCredentials) GetGoogleCardBillingAddressFormat() GoogleCardBillingAddressReq { +func (g *GooglePayCredentials) GetGoogleCardBillingAddressFormat() GoogleCardBillingAddressFormat { if g == nil { return "" } @@ -256,13 +255,6 @@ func (g *GooglePayCredentials) GetGoogleCardShippingAddressReq() bool { } return g.GoogleCardShippingAddressReq } -func (g *GooglePayCredentials) GetGoogleCardShippingAddressFormat() GoogleCardBillingAddressReq { - if g == nil { - return "" - } - - return g.GoogleCardShippingAddressFormat -} func (g *GooglePayCredentials) GetGoogleCardShippingPhoneReq() bool { if g == nil { return false @@ -295,17 +287,17 @@ func (g *GooglePayCredentials) GetGoogleAcquirerCountry() string { } type ( - GoogleEnvironment string - GoogleCardGateway string - GoogleCardAuthMethod string - GoogleTokenType string - GoogleCardNetwork string - GoogleCardBillingAddressReq string + GoogleEnvironment string + GoogleCardGateway string + GoogleCardAuthMethod string + GoogleTokenType string + GoogleCardNetwork string + GoogleCardBillingAddressFormat string ) const ( - GoogleCardBillingAddressReqMIN GoogleCardBillingAddressReq = "MIN" // Name, country code, and postal code (default). - GoogleCardBillingAddressReqFULL GoogleCardBillingAddressReq = "FULL" // Name, street address, locality, region, country code, and postal code. + GoogleCardBillingAddressReqMIN GoogleCardBillingAddressFormat = "MIN" // Name, country code, and postal code (default). + GoogleCardBillingAddressReqFULL GoogleCardBillingAddressFormat = "FULL" // Name, street address, locality, region, country code, and postal code. GoogleEnvironmentTEST GoogleEnvironment = "TEST" GoogleEnvironmentPROD GoogleEnvironment = "PRODUCTION" diff --git a/go.mod b/go.mod index 0fd4e8a..5a739b5 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,9 @@ module github.com/chargehive/configuration -go 1.22 +go 1.23 require ( - github.com/chargehive/proto v1.13.0 + github.com/chargehive/proto v1.14.0 github.com/go-playground/assert/v2 v2.2.0 github.com/go-playground/locales v0.14.1 github.com/go-playground/universal-translator v0.18.1 @@ -15,13 +15,13 @@ replace github.com/go-playground/validator/v10 => github.com/go-playground/valid require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/gabriel-vasile/mimetype v1.4.5 // indirect + github.com/gabriel-vasile/mimetype v1.4.6 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - golang.org/x/crypto v0.26.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.25.0 // indirect - golang.org/x/text v0.18.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + golang.org/x/crypto v0.28.0 // indirect + golang.org/x/net v0.30.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/text v0.19.0 // indirect + google.golang.org/protobuf v1.35.1 // indirect ) diff --git a/go.sum b/go.sum index 5fedb94..b48a1a3 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ -github.com/chargehive/proto v1.13.0 h1:0QnW/lwSZesV7f8ArVyHvnEocMAAsh6+of4kkjeb0RY= -github.com/chargehive/proto v1.13.0/go.mod h1:TSxF4AoWlaa2uwtEk3v+TC/jnKua1tk56m7Zi+85Dn0= +github.com/chargehive/proto v1.14.0 h1:6yWA8/6HdjmD3F/0NaLVjlVUTVnSRJBfFRWaP76errs= +github.com/chargehive/proto v1.14.0/go.mod h1:TSxF4AoWlaa2uwtEk3v+TC/jnKua1tk56m7Zi+85Dn0= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= -github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= +github.com/gabriel-vasile/mimetype v1.4.6 h1:3+PzJTKLkvgjeTbts6msPJt4DixhT4YtFNf1gtGe3zc= +github.com/gabriel-vasile/mimetype v1.4.6/go.mod h1:JX1qVKqZd40hUPpAfiNTe0Sne7hdfKSbOqqmkq8GCXc= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= @@ -20,15 +20,15 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/utils/generate.go b/utils/generate.go index ab7ca36..544b3cc 100644 --- a/utils/generate.go +++ b/utils/generate.go @@ -238,25 +238,24 @@ func buildSpec(conf Template) (object.Specification, error) { }, GooglePayPageId: chg, GooglePay: &connectorconfig.GooglePayCredentials{ - GoogleEnvironment: connectorconfig.GoogleEnvironmentTEST, - GoogleMerchantId: chg, - GoogleMerchantName: chg, - GoogleExistingMethodRequired: false, - GoogleEmailReq: false, - GoogleAcceptCard: true, - GoogleCardAuthMethods: []connectorconfig.GoogleCardAuthMethod{connectorconfig.GoogleCardAuthMethodPAN, connectorconfig.GoogleCardAuthMethod3DS}, - GoogleCardNetworks: []connectorconfig.GoogleCardNetwork{connectorconfig.GoogleCardNetworkAMEX, connectorconfig.GoogleCardNetworkDISCOVER, connectorconfig.GoogleCardNetworkMASTERCARD, connectorconfig.GoogleCardNetworkVISA}, - GoogleCardAllowPrepaid: true, - GoogleCardAllowCredit: true, - GoogleCardBillingAddressReq: false, - GoogleCardBillingAddressFormat: connectorconfig.GoogleCardBillingAddressReqMIN, - GoogleCardBillingPhoneReq: false, - GoogleCardShippingAddressReq: false, - GoogleCardShippingAddressFormat: connectorconfig.GoogleCardBillingAddressReqMIN, - GoogleCardShippingPhoneReq: false, - GoogleCardTokenType: connectorconfig.GoogleCardTokenTypeGATEWAY, - GoogleCardGateway: string(connectorconfig.GoogleCardGatewayVANTIV), - GoogleCardMerchantId: chg, + GoogleEnvironment: connectorconfig.GoogleEnvironmentTEST, + GoogleMerchantId: chg, + GoogleMerchantName: chg, + GoogleExistingMethodRequired: false, + GoogleEmailReq: false, + GoogleAcceptCard: true, + GoogleCardAuthMethods: []connectorconfig.GoogleCardAuthMethod{connectorconfig.GoogleCardAuthMethodPAN, connectorconfig.GoogleCardAuthMethod3DS}, + GoogleCardNetworks: []connectorconfig.GoogleCardNetwork{connectorconfig.GoogleCardNetworkAMEX, connectorconfig.GoogleCardNetworkDISCOVER, connectorconfig.GoogleCardNetworkMASTERCARD, connectorconfig.GoogleCardNetworkVISA}, + GoogleCardAllowPrepaid: true, + GoogleCardAllowCredit: true, + GoogleCardBillingAddressReq: false, + GoogleCardBillingAddressFormat: connectorconfig.GoogleCardBillingAddressReqMIN, + GoogleCardBillingPhoneReq: false, + GoogleCardShippingAddressReq: false, + GoogleCardShippingPhoneReq: false, + GoogleCardTokenType: connectorconfig.GoogleCardTokenTypeGATEWAY, + GoogleCardGateway: string(connectorconfig.GoogleCardGatewayVANTIV), + GoogleCardMerchantId: chg, }, }) From 01bc65ba3a9c2ee91423b8c24a8e9681f0474637 Mon Sep 17 00:00:00 2001 From: Brooke Bryan Date: Mon, 28 Oct 2024 12:38:08 +0000 Subject: [PATCH 17/27] Support all countries for adyen (#222) --- connectorconfig/adyen.go | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/connectorconfig/adyen.go b/connectorconfig/adyen.go index 10c8873..0cb7883 100644 --- a/connectorconfig/adyen.go +++ b/connectorconfig/adyen.go @@ -2,8 +2,6 @@ package connectorconfig import ( "encoding/json" - "strings" - "github.com/chargehive/configuration/environment" "github.com/chargehive/configuration/v1/connector" "github.com/chargehive/proto/golang/chargehive/chtype" @@ -67,18 +65,8 @@ func (c *AdyenCredentials) SupportsMethod(methodType chtype.PaymentMethodType, m return true } -var adyenAllowedCountires = []string{"AT", "AU", "BE", "CA", "CH", "CY", "CZ", "DE", "DK", "EE", "ES", "FI", "FR", "GB", "GR", "IE", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "NL", "NO", "PL", "PT", "SE", "SI", "SK", "US"} - func (c *AdyenCredentials) SupportsCountry(country string) bool { - if country == "" { - return true - } - for _, v := range adyenAllowedCountires { - if strings.EqualFold(v, country) { - return true - } - } - return false + return true } func (c *AdyenCredentials) CanPlanModeUse(mode environment.Mode) bool { From 9f52550a960ae51bee8305765b11fc6b24aae6cc Mon Sep 17 00:00:00 2001 From: Brooke Bryan Date: Mon, 28 Oct 2024 17:16:25 +0000 Subject: [PATCH 18/27] Additional operator validation (#223) --- selector/predicates.go | 2 +- utils/validate_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/selector/predicates.go b/selector/predicates.go index 281d43a..4d1e295 100644 --- a/selector/predicates.go +++ b/selector/predicates.go @@ -30,7 +30,7 @@ const ( type Predicate struct { Key Key `json:"key" yaml:"key" validate:"predicate-key"` - Operator PredicateOperator `json:"operator" yaml:"operator" validate:"oneof=Equal NotEqual In NotIn Exists DoesNotExists Gt Lt Like InLike"` + Operator PredicateOperator `json:"operator" yaml:"operator" validate:"oneof=Equal NotEqual In NotIn Exists DoesNotExists Gt Lt Like InLike NotLike NotInLike"` Conversion OperatorConversion `json:"conversion" yaml:"conversion" validate:"omitempty,oneof=TimeDow TimeMonth DurationSeconds DurationHours DurationDays"` Values []string `json:"values" yaml:"values"` } diff --git a/utils/validate_test.go b/utils/validate_test.go index d8d8a62..82b0129 100644 --- a/utils/validate_test.go +++ b/utils/validate_test.go @@ -47,7 +47,7 @@ func TestValidation(t *testing.T) { // _ = PrettyPrint(errs) assert.Equal(t, 2, len(errs)) assert.Equal(t, errs["PayPalWebsitePaymentsProCredentials.SupportedCurrencies[0]"], "SupportedCurrencies[0] must be one of [AUD BRL CAD CZK DKK EUR HKD HUF INR ILS JPY MYR MXN TWD NZD NOK PHP PLN GBP RUB SGD SEK CHF THB USD]") - assert.Equal(t, errs["Definition.Selector.Expressions[0].Operator"], "Operator must be one of [Equal NotEqual In NotIn Exists DoesNotExists Gt Lt Like InLike]") + assert.Equal(t, errs["Definition.Selector.Expressions[0].Operator"], "Operator must be one of [Equal NotEqual In NotIn Exists DoesNotExists Gt Lt Like InLike NotLike NotInLike]") } func TestLowerCaseName(t *testing.T) { From 46337a0cee081c460802f526a8fbb8e714feeacd Mon Sep 17 00:00:00 2001 From: Tom Kay Date: Fri, 8 Nov 2024 16:51:58 +0000 Subject: [PATCH 19/27] add ShouldTokenize to AttemptConfig to instruct assemble to tokenize payment methods (#224) --- v1/scheduler/attempt_config.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/v1/scheduler/attempt_config.go b/v1/scheduler/attempt_config.go index 152287f..5967d90 100644 --- a/v1/scheduler/attempt_config.go +++ b/v1/scheduler/attempt_config.go @@ -32,5 +32,7 @@ type AttemptConfig struct { PreferNetworkToken bool `json:"preferNetworkToken,omitempty" yaml:"preferNetworkToken,omitempty"` + ShouldTokenize bool `json:"shouldTokenize,omitempty" yaml:"shouldTokenize,omitempty"` + RecoveryAgentConnectorID string `json:"recoveryAgentConnectorID" yaml:"recoveryAgentConnectorID"` } From 11155f88e7ae5fa6d4ac60dad88a9f6ed422d687 Mon Sep 17 00:00:00 2001 From: Tom Kay Date: Mon, 18 Nov 2024 10:12:35 +0000 Subject: [PATCH 20/27] add merchantDescriptor to adyen, braintree, checkout, and paysafe (#225) --- connectorconfig/adyen.go | 16 +++++++++------- connectorconfig/braintree.go | 19 ++++++++++--------- connectorconfig/checkout.go | 1 + connectorconfig/paysafe.go | 1 + 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/connectorconfig/adyen.go b/connectorconfig/adyen.go index 0cb7883..0a8d053 100644 --- a/connectorconfig/adyen.go +++ b/connectorconfig/adyen.go @@ -2,6 +2,7 @@ package connectorconfig import ( "encoding/json" + "github.com/chargehive/configuration/environment" "github.com/chargehive/configuration/v1/connector" "github.com/chargehive/proto/golang/chargehive/chtype" @@ -15,13 +16,14 @@ const ( ) type AdyenCredentials struct { - Environment AdyenEnvironment `json:"environment" yaml:"environment" validate:"required,oneof=sandbox production"` - MerchantAccount string `json:"merchantAccount" yaml:"merchantAccount" validate:"required"` - ApiKey *string `json:"apiKey" yaml:"apiKey" validate:"required"` - ApiPrefix string `json:"apiPrefix" yaml:"apiPrefix" validate:"required"` - HMACKey *string `json:"hmacKey" yaml:"hmacKey" validate:"required"` - GooglePay *GooglePayCredentials `json:"googlePay,omitempty" yaml:"googlePay,omitempty"` - ApplePay *ApplePayCredentials `json:"applePay,omitempty" yaml:"applePay,omitempty"` + Environment AdyenEnvironment `json:"environment" yaml:"environment" validate:"required,oneof=sandbox production"` + MerchantAccount string `json:"merchantAccount" yaml:"merchantAccount" validate:"required"` + MerchantDescriptor string `json:"merchantDescriptor" yaml:"merchantDescriptor" validate:"-"` + ApiKey *string `json:"apiKey" yaml:"apiKey" validate:"required"` + ApiPrefix string `json:"apiPrefix" yaml:"apiPrefix" validate:"required"` + HMACKey *string `json:"hmacKey" yaml:"hmacKey" validate:"required"` + GooglePay *GooglePayCredentials `json:"googlePay,omitempty" yaml:"googlePay,omitempty"` + ApplePay *ApplePayCredentials `json:"applePay,omitempty" yaml:"applePay,omitempty"` } func (c *AdyenCredentials) GetMID() string { diff --git a/connectorconfig/braintree.go b/connectorconfig/braintree.go index 616422f..ca42601 100644 --- a/connectorconfig/braintree.go +++ b/connectorconfig/braintree.go @@ -19,15 +19,16 @@ const ( // https://articles.braintreepayments.com/control-panel/important-gateway-credentials type BraintreeCredentials struct { - PublicKey *string `json:"publicKey" yaml:"publicKey" validate:"required,gt=0"` - PrivateKey *string `json:"privateKey" yaml:"privateKey" validate:"required,gt=0"` - MerchantID string `json:"merchantID" yaml:"merchantID" validate:"required"` - MerchantAccountID string `json:"merchantAccountID" yaml:"merchantAccountID" validate:"-"` - Currency string `json:"currency" yaml:"currency" validate:"oneof=AED AMD AOA ARS AUD AWG AZN BAM BBD BDT BGN BIF BMD BND BOB BRL BSD BWP BYN BZD CAD CHF CLP CNY COP CRC CVE CZK DJF DKK DOP DZD EGP ETB EUR FJD FKP GBP GEL GHS GIP GMD GNF GTQ GYD HKD HNL HRK HTG HUF IDR ILS INR ISK JMD JPY KES KGS KHR KMF KRW KYD KZT LAK LBP LKR LRD LSL LTL MAD MDL MKD MNT MOP MUR MVR MWK MXN MYR MZN NAD NGN NIO NOK NPR NZD PAB PEN PGK PHP PKR PLN PYG QAR RON RSD RUB RWF SAR SBD SCR SEK SGD SHP SLL SOS SRD STD SVC SYP SZL THB TJS TOP TRY TTD TWD TZS UAH UGX USD UYU UZS VES VND VUV WST XAF XCD XOF XPF YER ZAR ZMK ZWD"` - Environment BraintreeEnvironment `json:"environment" yaml:"environment" validate:"oneof=sandbox production"` - GooglePay *GooglePayCredentials `json:"googlePay,omitempty" yaml:"googlePay,omitempty"` - ApplePay *ApplePayCredentials `json:"applePay,omitempty" yaml:"applePay,omitempty"` - TokenizationKey string `json:"tokenizationKey,omitempty" yaml:"tokenizationKey,omitempty" validate:"required_with=GooglePayEmbedded ApplePay,omitempty,gt=0"` + PublicKey *string `json:"publicKey" yaml:"publicKey" validate:"required,gt=0"` + PrivateKey *string `json:"privateKey" yaml:"privateKey" validate:"required,gt=0"` + MerchantID string `json:"merchantID" yaml:"merchantID" validate:"required"` + MerchantAccountID string `json:"merchantAccountID" yaml:"merchantAccountID" validate:"-"` + MerchantDescriptor string `json:"merchantDescriptor" yaml:"merchantDescriptor" validate:"-"` + Currency string `json:"currency" yaml:"currency" validate:"oneof=AED AMD AOA ARS AUD AWG AZN BAM BBD BDT BGN BIF BMD BND BOB BRL BSD BWP BYN BZD CAD CHF CLP CNY COP CRC CVE CZK DJF DKK DOP DZD EGP ETB EUR FJD FKP GBP GEL GHS GIP GMD GNF GTQ GYD HKD HNL HRK HTG HUF IDR ILS INR ISK JMD JPY KES KGS KHR KMF KRW KYD KZT LAK LBP LKR LRD LSL LTL MAD MDL MKD MNT MOP MUR MVR MWK MXN MYR MZN NAD NGN NIO NOK NPR NZD PAB PEN PGK PHP PKR PLN PYG QAR RON RSD RUB RWF SAR SBD SCR SEK SGD SHP SLL SOS SRD STD SVC SYP SZL THB TJS TOP TRY TTD TWD TZS UAH UGX USD UYU UZS VES VND VUV WST XAF XCD XOF XPF YER ZAR ZMK ZWD"` + Environment BraintreeEnvironment `json:"environment" yaml:"environment" validate:"oneof=sandbox production"` + GooglePay *GooglePayCredentials `json:"googlePay,omitempty" yaml:"googlePay,omitempty"` + ApplePay *ApplePayCredentials `json:"applePay,omitempty" yaml:"applePay,omitempty"` + TokenizationKey string `json:"tokenizationKey,omitempty" yaml:"tokenizationKey,omitempty" validate:"required_with=GooglePayEmbedded ApplePay,omitempty,gt=0"` } func (c *BraintreeCredentials) GetMID() string { diff --git a/connectorconfig/checkout.go b/connectorconfig/checkout.go index 63a26d2..63e402f 100644 --- a/connectorconfig/checkout.go +++ b/connectorconfig/checkout.go @@ -23,6 +23,7 @@ type CheckoutCredentials struct { Platform *string `json:"platform" yaml:"platform" validate:"required,oneof=default previous"` ProcessingChannelID string `json:"processingChannelId" yaml:"processingChannelId"` MerchantID string `json:"merchantID" yaml:"merchantID" validate:"required"` + MerchantDescriptor string `json:"merchantDescriptor" yaml:"merchantDescriptor" validate:"-"` Currency string `json:"currency" yaml:"currency" validate:"oneof=AED AFN ALL AMD ANG AOA ARS AUD AWG AZN BAM BBD BDT BGN BHD BIF BMD BND BOB BRL BSD BTN BWP BYN BZD CAD CDF CHF CLF CLP CNY COP CRC CUP CVE CZK DJF DKK DOP DZD EEK EGP ERN ETB EUR FJD FKP GBP GEL GHS GIP GMD GNF GTQ GYD HKD HNL HRK HTG HUF IDR ILS INR IQD IRR ISK JMD JOD JPY KES KGS KHR KMF KPW KRW KWD KYD KZT LAK LBP LKR LRD LSL LTL LVL LYD MAD MDL MGA MKD MMK MNT MOP MRO MUR MVR MWK MXN MYR MZN NAD NGN NIO NOK NPR NZD OMR PAB PEN PGK PHP PKR PLN PYG QAR RON RSD RUB RWF SAR SBD SCR SDG SEK SGD SHP SLL SOS SRD STD SVC SYP SZL THB TJS TMT TND TOP TRY TTD TWD TZS UAH UGX USD UYU UZS VEF VND VUV WST XAF XCD XOF XPF YER ZAR ZMW ZWL"` Environment CheckoutEnvironment `json:"environment" yaml:"environment" validate:"oneof=sandbox production"` GooglePay *GooglePayCredentials `json:"googlePay,omitempty" yaml:"googlePay,omitempty"` diff --git a/connectorconfig/paysafe.go b/connectorconfig/paysafe.go index 22fa01e..bc53c83 100644 --- a/connectorconfig/paysafe.go +++ b/connectorconfig/paysafe.go @@ -28,6 +28,7 @@ const ( type PaySafeCredentials struct { Acquirer string `json:"acquirer" yaml:"acquirer" validate:"-"` MerchantURL string `json:"merchantURL" yaml:"merchantURL" validate:"required"` + MerchantDescriptor string `json:"merchantDescriptor" yaml:"merchantDescriptor" validate:"-"` AccountID string `json:"accountID" yaml:"accountID" validate:"required"` APIUsername *string `json:"apiUsername" yaml:"apiUsername" validate:"required,gt=0"` APIPassword *string `json:"apiPassword" yaml:"apiPassword" validate:"required,gt=0"` From 95464a6145d32f6e83b91f272ccea282851d9762 Mon Sep 17 00:00:00 2001 From: Okechukwu Ugwu Date: Wed, 20 Nov 2024 16:22:10 +0000 Subject: [PATCH 21/27] Tokenex ACU configs (#226) - Add tokenex api ACU --- connectorconfig/library.go | 12 ++- .../{tokenex.go => tokenexaccountupdater.go} | 0 connectorconfig/tokenexapiaccountupdater.go | 73 +++++++++++++++++++ utils/generate.go | 8 ++ 4 files changed, 91 insertions(+), 2 deletions(-) rename connectorconfig/{tokenex.go => tokenexaccountupdater.go} (100%) create mode 100644 connectorconfig/tokenexapiaccountupdater.go diff --git a/connectorconfig/library.go b/connectorconfig/library.go index fcce0ab..9e3da5b 100644 --- a/connectorconfig/library.go +++ b/connectorconfig/library.go @@ -52,8 +52,9 @@ const ( LibraryRecaptcha Library = "recaptcha" // Updater Libraries - LibraryPaySafeAccountUpdater Library = "paysafe-accountupdater" - LibraryTokenExAccountUpdater Library = "tokenex-accountupdater" + LibraryPaySafeAccountUpdater Library = "paysafe-accountupdater" + LibraryTokenExAccountUpdater Library = "tokenex-accountupdater" + LibraryTokenExApiAccountUpdater Library = "tokenex-api-accountupdater" // Scheduler Libraries LibraryStickyIO Library = "sticky-io" @@ -345,6 +346,13 @@ var LibraryRegister = map[Library]LibraryDef{ return methodType == chtype.PAYMENT_METHOD_TYPE_CARD }, }, + LibraryTokenExApiAccountUpdater: { + DisplayName: "TokenEx API Account Updater", + Credentials: func() Credentials { return &TokenExApiAccountUpdaterCredentials{} }, + SupportsMethod: func(methodType chtype.PaymentMethodType, methodProvider chtype.PaymentMethodProvider) bool { + return methodType == chtype.PAYMENT_METHOD_TYPE_CARD + }, + }, LibraryTokenExNetworkTokenization: { DisplayName: "TokenEx Network Tokenization", Credentials: func() Credentials { return &TokenExNetworkTokenizationCredentials{} }, diff --git a/connectorconfig/tokenex.go b/connectorconfig/tokenexaccountupdater.go similarity index 100% rename from connectorconfig/tokenex.go rename to connectorconfig/tokenexaccountupdater.go diff --git a/connectorconfig/tokenexapiaccountupdater.go b/connectorconfig/tokenexapiaccountupdater.go new file mode 100644 index 0000000..87a269c --- /dev/null +++ b/connectorconfig/tokenexapiaccountupdater.go @@ -0,0 +1,73 @@ +package connectorconfig + +import ( + "encoding/json" + + "github.com/chargehive/configuration/environment" + "github.com/chargehive/configuration/v1/connector" + "github.com/chargehive/proto/golang/chargehive/chtype" +) + +type TokenExApiAccountUpdaterCredentials struct { + TokenexID string `json:"tokenexID" yaml:"tokenexID" validate:"required,gt=0"` + ApiKey *string `json:"apiKey" yaml:"apiKey" validate:"required,gt=0"` + + Environment TokenExEnvironment `json:"environment" yaml:"environment" validate:"oneof=sandbox production"` +} + +func (c *TokenExApiAccountUpdaterCredentials) GetMID() string { + return c.TokenexID +} + +func (c *TokenExApiAccountUpdaterCredentials) GetLibrary() Library { + return LibraryTokenExApiAccountUpdater +} + +func (c *TokenExApiAccountUpdaterCredentials) GetSupportedTypes() []LibraryType { + return []LibraryType{LibraryTypeMethodUpdater} +} + +func (c *TokenExApiAccountUpdaterCredentials) Validate() error { + return nil +} + +func (c *TokenExApiAccountUpdaterCredentials) GetSecureFields() []*string { + return []*string{c.ApiKey} +} + +func (c *TokenExApiAccountUpdaterCredentials) ToConnector() connector.Connector { + con := connector.Connector{Library: string(c.GetLibrary())} + con.Configuration, _ = json.Marshal(c) + return con +} + +func (c *TokenExApiAccountUpdaterCredentials) FromJson(input []byte) error { + return json.Unmarshal(input, c) +} + +func (c *TokenExApiAccountUpdaterCredentials) SupportsSca() bool { + return false +} + +func (c *TokenExApiAccountUpdaterCredentials) SupportsMethod(methodType chtype.PaymentMethodType, methodProvider chtype.PaymentMethodProvider) bool { + if !c.GetLibrary().SupportsMethod(methodType, methodProvider) { + return false + } + return true +} + +func (c *TokenExApiAccountUpdaterCredentials) SupportsCountry(country string) bool { + return true +} + +func (c *TokenExApiAccountUpdaterCredentials) CanPlanModeUse(environment.Mode) bool { + return true +} + +func (c *TokenExApiAccountUpdaterCredentials) IsRecoveryAgent() bool { + return false +} + +func (c *TokenExApiAccountUpdaterCredentials) Supports3RI() bool { + return false +} diff --git a/utils/generate.go b/utils/generate.go index 544b3cc..295f3fc 100644 --- a/utils/generate.go +++ b/utils/generate.go @@ -41,6 +41,7 @@ const ( confConnWorldPay Template = "con_worldPay" confConnYapstone Template = "con_yapstone" confConnTokenEx Template = "con_tokenex" + confConnTokenExApi Template = "con_tokenex_api" confConnTokenExNT Template = "con_tokenex_network_tokenization" confConnFlexPay Template = "con_flexpay" @@ -329,6 +330,13 @@ func buildSpec(conf Template) (object.Specification, error) { Region: connectorconfig.TokenExRegionUS, }) return connector.Connector{Library: string(connectorconfig.LibraryTokenExAccountUpdater), Configuration: j}, nil + case confConnTokenExApi: + j, _ := json.Marshal(connectorconfig.TokenExApiAccountUpdaterCredentials{ + TokenexID: chg, + ApiKey: &chg, + Environment: connectorconfig.TokenExEnvironmentSandbox, + }) + return connector.Connector{Library: string(connectorconfig.LibraryTokenExApiAccountUpdater), Configuration: j}, nil case confConnTokenExNT: j, _ := json.Marshal(connectorconfig.TokenExNetworkTokenizationCredentials{ Environment: connectorconfig.TokenExEnvironmentSandbox, From 91495d51c0fb2780b12fa75bb1d665ffb555d819 Mon Sep 17 00:00:00 2001 From: Okechukwu Ugwu Date: Wed, 20 Nov 2024 16:42:08 +0000 Subject: [PATCH 22/27] keep config field name consistent (#227) --- connectorconfig/tokenexapiaccountupdater.go | 4 ++-- utils/generate.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/connectorconfig/tokenexapiaccountupdater.go b/connectorconfig/tokenexapiaccountupdater.go index 87a269c..3e228ec 100644 --- a/connectorconfig/tokenexapiaccountupdater.go +++ b/connectorconfig/tokenexapiaccountupdater.go @@ -9,14 +9,14 @@ import ( ) type TokenExApiAccountUpdaterCredentials struct { - TokenexID string `json:"tokenexID" yaml:"tokenexID" validate:"required,gt=0"` + TokenExID string `json:"tokenExID" yaml:"tokenExID" validate:"required,gt=0"` ApiKey *string `json:"apiKey" yaml:"apiKey" validate:"required,gt=0"` Environment TokenExEnvironment `json:"environment" yaml:"environment" validate:"oneof=sandbox production"` } func (c *TokenExApiAccountUpdaterCredentials) GetMID() string { - return c.TokenexID + return c.TokenExID } func (c *TokenExApiAccountUpdaterCredentials) GetLibrary() Library { diff --git a/utils/generate.go b/utils/generate.go index 295f3fc..5168958 100644 --- a/utils/generate.go +++ b/utils/generate.go @@ -332,7 +332,7 @@ func buildSpec(conf Template) (object.Specification, error) { return connector.Connector{Library: string(connectorconfig.LibraryTokenExAccountUpdater), Configuration: j}, nil case confConnTokenExApi: j, _ := json.Marshal(connectorconfig.TokenExApiAccountUpdaterCredentials{ - TokenexID: chg, + TokenExID: chg, ApiKey: &chg, Environment: connectorconfig.TokenExEnvironmentSandbox, }) From e9deb2929d055b464fe9af40a2248fde56ab6bf0 Mon Sep 17 00:00:00 2001 From: Okechukwu Ugwu Date: Wed, 20 Nov 2024 17:23:24 +0000 Subject: [PATCH 23/27] Fix Library validation (#228) add "tokenex-api-accountupdater" as a valid library type --- v1/connector/connector.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v1/connector/connector.go b/v1/connector/connector.go index 28b53f7..9046c96 100644 --- a/v1/connector/connector.go +++ b/v1/connector/connector.go @@ -25,7 +25,7 @@ const ( // Connector is a configuration file for a single payment processing entity type Connector struct { ProcessingState ProcessingState `json:"processingState,omitempty" yaml:"processingState,omitempty"` - Library string `json:"library" yaml:"library" validate:"omitempty,oneof=recaptcha flexpay adyen bluesnap gpayments nuvei inoviopay threedsecureio sandbox sandbanx applepay authorize braintree qualpay stripe paysafe worldpay paypal-websitepaymentspro paypal-expresscheckout vindicia maxmind cybersource paysafe-accountupdater bottomline checkout kount clearhaus trust-payments cwams yapstone tokenex-accountupdater tokenex-networktokenization sticky-io googlepay"` + Library string `json:"library" yaml:"library" validate:"omitempty,oneof=recaptcha flexpay adyen bluesnap gpayments nuvei inoviopay threedsecureio sandbox sandbanx applepay authorize braintree qualpay stripe paysafe worldpay paypal-websitepaymentspro paypal-expresscheckout vindicia maxmind cybersource paysafe-accountupdater bottomline checkout kount clearhaus trust-payments cwams yapstone tokenex-accountupdater tokenex-api-accountupdater tokenex-networktokenization sticky-io googlepay"` Configuration []byte `json:"configuration" yaml:"configuration" validate:"required"` ConfigID string `json:"configId,omitempty" yaml:"configId,omitempty"` ConfigAuth string `json:"configAuth,omitempty" yaml:"configAuth,omitempty"` From f5e3239d3caf37d2d6312fab0b4f27c33b8324ee Mon Sep 17 00:00:00 2001 From: Okechukwu Ugwu Date: Mon, 25 Nov 2024 16:12:10 +0000 Subject: [PATCH 24/27] Add ability to control charge type (default or adhoc) for a given attempt config (#229) * Add ability to control charge type (default or adhoc) for a given attempt config * rename * fix validate string --- v1/scheduler/attempt_config.go | 2 ++ v1/scheduler/enums.go | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/v1/scheduler/attempt_config.go b/v1/scheduler/attempt_config.go index 5967d90..ca9d9f3 100644 --- a/v1/scheduler/attempt_config.go +++ b/v1/scheduler/attempt_config.go @@ -35,4 +35,6 @@ type AttemptConfig struct { ShouldTokenize bool `json:"shouldTokenize,omitempty" yaml:"shouldTokenize,omitempty"` RecoveryAgentConnectorID string `json:"recoveryAgentConnectorID" yaml:"recoveryAgentConnectorID"` + + ChargeType ChargeType `json:"chargeType" yaml:"chargeType" validate:"oneof='' unscheduled"` } diff --git a/v1/scheduler/enums.go b/v1/scheduler/enums.go index c9d168e..3cb38ea 100644 --- a/v1/scheduler/enums.go +++ b/v1/scheduler/enums.go @@ -165,3 +165,10 @@ const ( // ConnectorRetryTypePanToToken Use the Pan first, cascade to Token if available ConnectorRetryTypePanToToken ConnectorRetryType = "pan-token" ) + +type ChargeType string + +const ( + ChargeTypeDefault ChargeType = "" + ChargeTypeUnscheduled = "unscheduled" +) From 3ee27eb653c6a448b7cda0a51b5f7ad1207b89cf Mon Sep 17 00:00:00 2001 From: Tom Kay Date: Thu, 12 Dec 2024 16:40:30 +0000 Subject: [PATCH 25/27] Rate limit (#230) * add rate limit policy * add definition * fix typo --- v1/policy/fraud.go | 2 +- v1/policy/init.go | 9 +++++++ v1/policy/rate_limit.go | 55 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 v1/policy/rate_limit.go diff --git a/v1/policy/fraud.go b/v1/policy/fraud.go index b92bff3..c7fba06 100644 --- a/v1/policy/fraud.go +++ b/v1/policy/fraud.go @@ -79,7 +79,7 @@ func NewFraudDefinition(d *object.Definition) (*FraudDefinition, error) { // FraudDefinition is the Fraud config object definition type FraudDefinition struct{ def *object.Definition } -// Definition returns the ChargeExpiryDefinition structure +// Definition returns the FraudDefinition structure func (d *FraudDefinition) Definition() *object.Definition { return d.def } // MarshalJSON returns the JSON value for the FraudDefinition diff --git a/v1/policy/init.go b/v1/policy/init.go index 503343b..561b9f4 100644 --- a/v1/policy/init.go +++ b/v1/policy/init.go @@ -10,6 +10,7 @@ func GetHandlers() []object.KindHandler { funcs = append(funcs, chargeExpiryPolicy()...) funcs = append(funcs, chargePolicy()...) funcs = append(funcs, methodUpgradePolicy()...) + funcs = append(funcs, rateLimitPolicy()...) funcs = append(funcs, cascadePolicy()...) funcs = append(funcs, methodLockPolicy()...) funcs = append(funcs, methodVerifyPolicy()...) @@ -57,6 +58,14 @@ func methodUpgradePolicy() []object.KindHandler { } } +func rateLimitPolicy() []object.KindHandler { + o := RateLimitPolicy{} + return []object.KindHandler{ + object.NewKindHandler(o.GetKind(), object.KindHandlerDefaultVersion, func() object.Specification { return &RateLimitPolicy{} }), + object.NewKindHandler(o.GetKind(), o.GetVersion(), func() object.Specification { return &RateLimitPolicy{} }), + } +} + func cascadePolicy() []object.KindHandler { o := CascadePolicy{} return []object.KindHandler{ diff --git a/v1/policy/rate_limit.go b/v1/policy/rate_limit.go new file mode 100644 index 0000000..7af64c4 --- /dev/null +++ b/v1/policy/rate_limit.go @@ -0,0 +1,55 @@ +package policy + +import ( + "encoding/json" + "errors" + + "github.com/chargehive/configuration/object" +) + +// KindPolicyRateLimit is the identifier for a RateLimitPolicy config +const KindPolicyRateLimit object.Kind = "RateLimitPolicy" + +type RateLimitKey string + +const ( + RateLimitKeyChargePlacementID RateLimitKey = "PlacementID" + RateLimitKeyMerchantReference RateLimitKey = "MerchantReference" + RateLimitKeyCorrelationID RateLimitKey = "CorrelationID" + RateLimitKeyBillingProfileID RateLimitKey = "BillingProfileID" + RateLimitKeyIP RateLimitKey = "IP" + RateLimitKeyUserAgent RateLimitKey = "UserAgent" + RateLimitKeyPlatform RateLimitKey = "Platform" +) + +type RateLimitPolicy struct { + // LimitProperty is the property to limit the rate by, global if empty + LimitProperty RateLimitKey `json:"limitProperty" yaml:"limitProperty" validate:"oneof=PlacementID MerchantReference CorrelationID BillingProfileID IP UserAgent Platform"` + // HardLimit is the maximum number of requests allowed in the window + HardLimit int32 `json:"hardLimit" yaml:"hardLimit" validate:"required,min=1"` + // Window is the time window in minutes that the limit is applied to + Window int32 `json:"window" yaml:"window" validate:"required,min=1"` +} + +func (r RateLimitPolicy) GetKind() object.Kind { return KindPolicyRateLimit } + +func (r RateLimitPolicy) GetVersion() string { return "v1" } + +type RateLimitDefinition struct{ def *object.Definition } + +// NewRateLimitDefinition creates a new RateLimitDefinition +func NewRateLimitDefinition(d *object.Definition) (*RateLimitDefinition, error) { + if _, ok := d.Spec.(*RateLimitPolicy); ok { + return &RateLimitDefinition{def: d}, nil + } + return nil, errors.New("invalid Rate Limit Policy object") +} + +// Definition returns the RateLimitDefinition structure +func (d *RateLimitDefinition) Definition() *object.Definition { return d.def } + +// MarshalJSON returns the JSON value for the RateLimitDefinition +func (d *RateLimitDefinition) MarshalJSON() ([]byte, error) { return json.Marshal(d.def) } + +// Spec returns the RateLimitPolicy contained within the RateLimitDefinition +func (d *RateLimitDefinition) Spec() *RateLimitPolicy { return d.def.Spec.(*RateLimitPolicy) } From 2788c2ec96d7cbbcee7ea530cc8dd8a5e0a27ad7 Mon Sep 17 00:00:00 2001 From: Tom Kay Date: Thu, 12 Dec 2024 18:03:15 +0000 Subject: [PATCH 26/27] update rate limit options (#231) * update rate limit options * limit ip options --- v1/policy/rate_limit.go | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/v1/policy/rate_limit.go b/v1/policy/rate_limit.go index 7af64c4..6b7f6de 100644 --- a/v1/policy/rate_limit.go +++ b/v1/policy/rate_limit.go @@ -12,19 +12,29 @@ const KindPolicyRateLimit object.Kind = "RateLimitPolicy" type RateLimitKey string +type RateLimitIPOptions struct { + MaskBits int32 `json:"maskBits" yaml:"maskBits" validate:"required,oneof=16 24 32"` +} + const ( - RateLimitKeyChargePlacementID RateLimitKey = "PlacementID" - RateLimitKeyMerchantReference RateLimitKey = "MerchantReference" - RateLimitKeyCorrelationID RateLimitKey = "CorrelationID" - RateLimitKeyBillingProfileID RateLimitKey = "BillingProfileID" - RateLimitKeyIP RateLimitKey = "IP" - RateLimitKeyUserAgent RateLimitKey = "UserAgent" - RateLimitKeyPlatform RateLimitKey = "Platform" + RateLimitKeyChargePlacementID RateLimitKey = "PlacementID" + RateLimitKeyMerchantReference RateLimitKey = "MerchantReference" + RateLimitKeyCorrelationID RateLimitKey = "CorrelationID" + RateLimitKeyBillingProfileID RateLimitKey = "BillingProfileID" + RateLimitKeyIP RateLimitKey = "IP" + RateLimitKeyCurrency RateLimitKey = "Currency" + RateLimitKeyUserAgent RateLimitKey = "UserAgent" + RateLimitKeyDeviceType RateLimitKey = "DeviceType" + RateLimitKeyDeviceBrowser RateLimitKey = "DeviceBrowser" + RateLimitKeyDeviceBrowserVersion RateLimitKey = "DeviceBrowserVersion" + RateLimitKeyDeviceFingerprint RateLimitKey = "DeviceFingerprint" ) type RateLimitPolicy struct { // LimitProperty is the property to limit the rate by, global if empty - LimitProperty RateLimitKey `json:"limitProperty" yaml:"limitProperty" validate:"oneof=PlacementID MerchantReference CorrelationID BillingProfileID IP UserAgent Platform"` + LimitProperty RateLimitKey `json:"limitProperty" yaml:"limitProperty" validate:"oneof=PlacementID MerchantReference CorrelationID BillingProfileID IP Currency UserAgent DeviceType DeviceBrowser DeviceBrowserVersion DeviceFingerprint"` + // IPOptions allows for additional rate limiting options for IP based rate limits + IPOptions *RateLimitIPOptions `json:"ipOptions" yaml:"ipOptions" validate:"required_if=LimitProperty IP"` // HardLimit is the maximum number of requests allowed in the window HardLimit int32 `json:"hardLimit" yaml:"hardLimit" validate:"required,min=1"` // Window is the time window in minutes that the limit is applied to From 64c0b8638fc07d5980354e59b1777ebab444ee86 Mon Sep 17 00:00:00 2001 From: Tom Kay Date: Fri, 13 Dec 2024 12:58:20 +0000 Subject: [PATCH 27/27] Optional property (#232) * optional property * use omitempty as optional --- v1/policy/rate_limit.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v1/policy/rate_limit.go b/v1/policy/rate_limit.go index 6b7f6de..0579951 100644 --- a/v1/policy/rate_limit.go +++ b/v1/policy/rate_limit.go @@ -32,7 +32,7 @@ const ( type RateLimitPolicy struct { // LimitProperty is the property to limit the rate by, global if empty - LimitProperty RateLimitKey `json:"limitProperty" yaml:"limitProperty" validate:"oneof=PlacementID MerchantReference CorrelationID BillingProfileID IP Currency UserAgent DeviceType DeviceBrowser DeviceBrowserVersion DeviceFingerprint"` + LimitProperty RateLimitKey `json:"limitProperty" yaml:"limitProperty" validate:"omitempty,oneof=PlacementID MerchantReference CorrelationID BillingProfileID IP Currency UserAgent DeviceType DeviceBrowser DeviceBrowserVersion DeviceFingerprint"` // IPOptions allows for additional rate limiting options for IP based rate limits IPOptions *RateLimitIPOptions `json:"ipOptions" yaml:"ipOptions" validate:"required_if=LimitProperty IP"` // HardLimit is the maximum number of requests allowed in the window