From a0f49df251a8d82edf8399bb3311300344f4ca1e Mon Sep 17 00:00:00 2001 From: Nick Logan Date: Fri, 24 May 2024 12:55:14 +0000 Subject: [PATCH 1/4] Make IP address optional when reporting transactions --- CHANGELOG.md | 8 ++++ README.md | 5 +- src/MinFraud/ReportTransaction.php | 46 ++++++++++++------- .../ReportTransactionTest.php | 35 ++++++++++++-- 4 files changed, 73 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34ee593..0410f86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ CHANGELOG ========= +3.1.0 +------------------ + +* Updated `MaxMind\MinFraud\ReportTransaction` to make the `ip_address` + parameter optional. Now the `tag` and at least one of the following + parameters must be supplied: `ip_address`, `maxmind_id`, `minfraud_id`, + `transaction_id`. + 3.0.1 (2024-05-02) ------------------ diff --git a/README.md b/README.md index 9c834a7..aff59e5 100644 --- a/README.md +++ b/README.md @@ -282,8 +282,9 @@ All externally visible exceptions are in the `\MaxMind\Exception` namespace. The possible exceptions are: * `InvalidInputException` - This will be thrown when the `->report()` method is - called with invalid input data or when the required `ip_address` or `tag` - fields are missing. + called with invalid input data or when the required fields are missing. The + required fields are `tag` and one or more of the following: `ip_address`, + `maxmind_id`, `minfraud_id`, or `transaction_id`. * `AuthenticationException` - This will be thrown on calling `->report()`, when the server is unable to authenticate the request, e.g., if the license key or account ID is invalid. diff --git a/src/MinFraud/ReportTransaction.php b/src/MinFraud/ReportTransaction.php index d52e6e2..d321096 100644 --- a/src/MinFraud/ReportTransaction.php +++ b/src/MinFraud/ReportTransaction.php @@ -46,9 +46,11 @@ public function __construct( * @param array $values An array of transaction parameters. The keys are the same * as the JSON keys. You may use either this or the named * arguments, but not both. - * @param string $ipAddress Required. The IP address of the customer placing the + * @param string $ipAddress Optional. The IP address of the customer placing the * order. This should be passed as a string like - * "44.55.66.77" or "2001:db8::2:1". + * "44.55.66.77" or "2001:db8::2:1". This field is not + * required if you provide at least one of the transaction's + * maxmindId, minfraudId, or transactionId. * @param string $tag Required. A string indicating the likelihood that a * transaction may be fraudulent. Possible values: * not_fraud, suspected_fraud, spam_or_abuse, or @@ -59,22 +61,25 @@ public function __construct( * a minFraud Standard or Premium request. These IDs are * returned in the maxmindID field of a response for a * successful minFraud request. This field is not - * required, but you are encouraged to provide it, if - * possible. + * required if you provide at least one of the transaction's + * ipAddress, minfraudId, or transactionId. You are + * encouraged to provide it, if possible. * @param string $minfraudId Optional. A UUID that identifies a minFraud Score, * minFraud Insights, or minFraud Factors request. This * ID is returned at /id in the response. This field is - * not required, but you are encouraged to provide it if - * the request was made to one of these services. + * not required if you provide at least one of the transaction's + * ipAddress, maxmindId, or transactionId. You are encouraged to + * provide it the request was made to one of these services. * @param string $notes Optional. Your notes on the fraud tag associated with * the transaction. We manually review many reported * transactions to improve our scoring for you so any * additional details to help us understand context are * helpful. * @param string $transactionId Optional. The transaction ID you originally passed to - * minFraud. This field is not required, but you are - * encouraged to provide it or the transaction's - * maxmind_id or minfraud_id. + * minFraud. This field is not required if you provide at + * least one of the transaction's ipAddress, maxmindId, or + * minfraudId. You are encouraged to provide it or the + * transaction's maxmind_id or minfraud_id. * * @throws InvalidInputException when the request has missing or invalid * data @@ -116,18 +121,27 @@ public function report( $this->verifyEmpty($values); } + if ($ipAddress === null + && $minfraudId === null + && ($maxmindId === null || $maxmindId === '') + && ($transactionId === null || $transactionId === '') + ) { + throw new InvalidInputException( + 'The user must pass at least one of the following: ' . + 'ipAddress, minfraudId, maxmindId, transactionId.' + ); + } + if ($chargebackCode !== null) { $values['chargeback_code'] = $chargebackCode; } - if ($ipAddress === null) { - // This is required so we always throw an exception if it is not set - throw new InvalidInputException('An IP address is required'); - } - if (!filter_var($ipAddress, \FILTER_VALIDATE_IP)) { - $this->maybeThrowInvalidInputException("$ipAddress is an invalid IP address"); + if ($ipAddress !== null) { + if (!filter_var($ipAddress, \FILTER_VALIDATE_IP)) { + $this->maybeThrowInvalidInputException("$ipAddress is an invalid IP address"); + } + $values['ip_address'] = $ipAddress; } - $values['ip_address'] = $ipAddress; if ($maxmindId !== null) { if (\strlen($maxmindId) !== 8) { diff --git a/tests/MaxMind/Test/MinFraud/ReportTransaction/ReportTransactionTest.php b/tests/MaxMind/Test/MinFraud/ReportTransaction/ReportTransactionTest.php index 76982c9..6a93247 100644 --- a/tests/MaxMind/Test/MinFraud/ReportTransaction/ReportTransactionTest.php +++ b/tests/MaxMind/Test/MinFraud/ReportTransaction/ReportTransactionTest.php @@ -62,13 +62,42 @@ public function testRequestsWithNulls(): void ); } + public function testRequiredFields(): void + { + $this->expectNotToPerformAssertions(); + + $req = [ + 'ip_address' => '1.1.1.1', + 'tag' => 'not_fraud', + ]; + $this->createReportTransactionRequest($req, 1)->report($req); + + $req = [ + 'maxmind_id' => '12345678', + 'tag' => 'not_fraud', + ]; + $this->createReportTransactionRequest($req, 1)->report($req); + + $req = [ + 'minfraud_id' => '58fa38d8-4b87-458b-a22b-f00eda1aa20d', + 'tag' => 'not_fraud', + ]; + $this->createReportTransactionRequest($req, 1)->report($req); + + $req = [ + 'tag' => 'not_fraud', + 'transaction_id' => 'abc123', + ]; + $this->createReportTransactionRequest($req, 1)->report($req); + } + /** * @dataProvider requestsMissingRequiredFields */ public function testMissingRequiredFields(array $req): void { $this->expectException(InvalidInputException::class); - $this->expectExceptionMessageMatches('/Expected|is required/'); + $this->expectExceptionMessageMatches('/Expected|is required|must pass at least one of the following/'); $this->createReportTransactionRequest( $req, @@ -82,7 +111,7 @@ public function testMissingRequiredFields(array $req): void public function testMissingRequiredFieldsWithoutValidation(array $req): void { $this->expectException(InvalidInputException::class); - $this->expectExceptionMessageMatches('/Expected|is required/'); + $this->expectExceptionMessageMatches('/Expected|is required|must pass at least one of the following/'); $this->createReportTransactionRequest( $req, @@ -94,7 +123,7 @@ public function testMissingRequiredFieldsWithoutValidation(array $req): void public static function requestsMissingRequiredFields(): array { return [ - 'Missing ip_address' => [ + 'Missing one of ip_address, maxmind_id, minfraud_id, or transaction_id' => [ ['tag' => 'not_fraud'], ], 'Missing tag' => [ From 77bd5bf3206d3504322dba87f5862ffc4b894479 Mon Sep 17 00:00:00 2001 From: Nick Logan Date: Thu, 30 May 2024 14:13:10 +0000 Subject: [PATCH 2/4] Do one-of field validation after individual field validation --- src/MinFraud/ReportTransaction.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/MinFraud/ReportTransaction.php b/src/MinFraud/ReportTransaction.php index d321096..b97f33c 100644 --- a/src/MinFraud/ReportTransaction.php +++ b/src/MinFraud/ReportTransaction.php @@ -121,17 +121,6 @@ public function report( $this->verifyEmpty($values); } - if ($ipAddress === null - && $minfraudId === null - && ($maxmindId === null || $maxmindId === '') - && ($transactionId === null || $transactionId === '') - ) { - throw new InvalidInputException( - 'The user must pass at least one of the following: ' . - 'ipAddress, minfraudId, maxmindId, transactionId.' - ); - } - if ($chargebackCode !== null) { $values['chargeback_code'] = $chargebackCode; } @@ -180,6 +169,17 @@ public function report( $values['transaction_id'] = $transactionId; } + if ($ipAddress === null + && $minfraudId === null + && ($maxmindId === null || $maxmindId === '') + && ($transactionId === null || $transactionId === '') + ) { + throw new InvalidInputException( + 'The user must pass at least one of the following: ' . + 'ipAddress, minfraudId, maxmindId, transactionId.' + ); + } + $url = self::$basePath . 'transactions/report'; $this->client->post('ReportTransaction', $url, $values); } From 364fb6496d9b964eb211c121207b3f940774843f Mon Sep 17 00:00:00 2001 From: Nick Logan Date: Thu, 30 May 2024 14:16:26 +0000 Subject: [PATCH 3/4] Check for empty values In most situations the individual field validation ensures these fields aren't empty strings. However when validation is disabled it is possible for empty strings to reach this conditional. --- src/MinFraud/ReportTransaction.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/MinFraud/ReportTransaction.php b/src/MinFraud/ReportTransaction.php index b97f33c..964ff3f 100644 --- a/src/MinFraud/ReportTransaction.php +++ b/src/MinFraud/ReportTransaction.php @@ -169,8 +169,9 @@ public function report( $values['transaction_id'] = $transactionId; } - if ($ipAddress === null - && $minfraudId === null + // One of these fields is required so we always throw an exception if one is not set + if (($ipAddress === null || $ipAddress === '') + && ($minfraudId === null || $minfraudId === '') && ($maxmindId === null || $maxmindId === '') && ($transactionId === null || $transactionId === '') ) { From 6cbfc425e380518b170bb601b62c6e0ceca0fb41 Mon Sep 17 00:00:00 2001 From: Nick Logan Date: Thu, 30 May 2024 14:30:49 +0000 Subject: [PATCH 4/4] Clean up documentation --- CHANGELOG.md | 4 ++-- README.md | 4 ++-- src/MinFraud/ReportTransaction.php | 17 +++++++++-------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0410f86..a7c61c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,8 @@ CHANGELOG * Updated `MaxMind\MinFraud\ReportTransaction` to make the `ip_address` parameter optional. Now the `tag` and at least one of the following - parameters must be supplied: `ip_address`, `maxmind_id`, `minfraud_id`, - `transaction_id`. + parameters must be supplied: `ipAddress`, `maxmindId`, `minfraudId`, + `transactionId`. 3.0.1 (2024-05-02) ------------------ diff --git a/README.md b/README.md index aff59e5..fce5f4e 100644 --- a/README.md +++ b/README.md @@ -283,8 +283,8 @@ The possible exceptions are: * `InvalidInputException` - This will be thrown when the `->report()` method is called with invalid input data or when the required fields are missing. The - required fields are `tag` and one or more of the following: `ip_address`, - `maxmind_id`, `minfraud_id`, or `transaction_id`. + required fields are `tag` and one or more of the following: `ipAddress`, + `maxmindId`, `minfraudId`, or `transactionId`. * `AuthenticationException` - This will be thrown on calling `->report()`, when the server is unable to authenticate the request, e.g., if the license key or account ID is invalid. diff --git a/src/MinFraud/ReportTransaction.php b/src/MinFraud/ReportTransaction.php index 964ff3f..d92e99a 100644 --- a/src/MinFraud/ReportTransaction.php +++ b/src/MinFraud/ReportTransaction.php @@ -50,7 +50,7 @@ public function __construct( * order. This should be passed as a string like * "44.55.66.77" or "2001:db8::2:1". This field is not * required if you provide at least one of the transaction's - * maxmindId, minfraudId, or transactionId. + * `maxmindId`, `minfraudId`, or `transactionId`. * @param string $tag Required. A string indicating the likelihood that a * transaction may be fraudulent. Possible values: * not_fraud, suspected_fraud, spam_or_abuse, or @@ -59,17 +59,18 @@ public function __construct( * processor indicating the reason for the chargeback. * @param string $maxmindId Optional. A unique eight character string identifying * a minFraud Standard or Premium request. These IDs are - * returned in the maxmindID field of a response for a + * returned in the `maxmindID` field of a response for a * successful minFraud request. This field is not * required if you provide at least one of the transaction's - * ipAddress, minfraudId, or transactionId. You are + * `ipAddress`, `minfraudId`, or `transactionId`. You are * encouraged to provide it, if possible. * @param string $minfraudId Optional. A UUID that identifies a minFraud Score, * minFraud Insights, or minFraud Factors request. This * ID is returned at /id in the response. This field is * not required if you provide at least one of the transaction's - * ipAddress, maxmindId, or transactionId. You are encouraged to - * provide it the request was made to one of these services. + * `ipAddress`, `maxmindId`, or `transactionId`. You are + * encouraged to provide it if the request was made to one of + * these services. * @param string $notes Optional. Your notes on the fraud tag associated with * the transaction. We manually review many reported * transactions to improve our scoring for you so any @@ -77,9 +78,9 @@ public function __construct( * helpful. * @param string $transactionId Optional. The transaction ID you originally passed to * minFraud. This field is not required if you provide at - * least one of the transaction's ipAddress, maxmindId, or - * minfraudId. You are encouraged to provide it or the - * transaction's maxmind_id or minfraud_id. + * least one of the transaction's `ipAddress`, `maxmindId`, or + * `minfraudId`. You are encouraged to provide it or the + * transaction's `maxmindId` or `minfraudId`. * * @throws InvalidInputException when the request has missing or invalid * data