1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/payments/core/payment_details_validation.h"
6
7 #include <set>
8 #include <vector>
9
10 #include "components/payments/core/payment_details.h"
11 #include "components/payments/core/payments_validators.h"
12
13 namespace payments {
14 namespace {
15
16 // Validates ShippingOption or PaymentItem, which happen to have identical
17 // fields, except for "id", which is present only in ShippingOption.
18 template <typename T>
ValidateShippingOptionOrPaymentItem(const T & item,const PaymentItem & total,std::string * error_message)19 bool ValidateShippingOptionOrPaymentItem(const T& item,
20 const PaymentItem& total,
21 std::string* error_message) {
22 if (!item.amount) {
23 *error_message = "Amount required";
24 return false;
25 }
26
27 if (item.amount->currency.empty()) {
28 *error_message = "Currency code required";
29 return false;
30 }
31
32 if (item.amount->value.empty()) {
33 *error_message = "Currency value required";
34 return false;
35 }
36
37 if (!payments::PaymentsValidators::IsValidCurrencyCodeFormat(
38 item.amount->currency, error_message)) {
39 return false;
40 }
41
42 if (!payments::PaymentsValidators::IsValidAmountFormat(item.amount->value,
43 error_message)) {
44 return false;
45 }
46 return true;
47 }
48
ValidateDisplayItems(const std::vector<PaymentItem> & items,const PaymentItem & total,std::string * error_message)49 bool ValidateDisplayItems(const std::vector<PaymentItem>& items,
50 const PaymentItem& total,
51 std::string* error_message) {
52 for (const auto& item : items) {
53 if (!ValidateShippingOptionOrPaymentItem(item, total, error_message))
54 return false;
55 }
56 return true;
57 }
58
ValidateShippingOptions(const std::vector<PaymentShippingOption> & options,const PaymentItem & total,std::string * error_message)59 bool ValidateShippingOptions(const std::vector<PaymentShippingOption>& options,
60 const PaymentItem& total,
61 std::string* error_message) {
62 std::set<std::string> uniqueIds;
63 for (const auto& option : options) {
64 if (option.id.empty()) {
65 *error_message = "ShippingOption id required";
66 return false;
67 }
68
69 if (uniqueIds.find(option.id) != uniqueIds.end()) {
70 *error_message = "Duplicate shipping option identifiers are not allowed";
71 return false;
72 }
73 uniqueIds.insert(option.id);
74
75 if (!ValidateShippingOptionOrPaymentItem(option, total, error_message))
76 return false;
77 }
78 return true;
79 }
80
ValidatePaymentDetailsModifiers(const std::vector<PaymentDetailsModifier> & modifiers,const PaymentItem & total,std::string * error_message)81 bool ValidatePaymentDetailsModifiers(
82 const std::vector<PaymentDetailsModifier>& modifiers,
83 const PaymentItem& total,
84 std::string* error_message) {
85 if (modifiers.empty()) {
86 *error_message = "Must specify at least one payment details modifier";
87 return false;
88 }
89
90 for (const auto& modifier : modifiers) {
91 if (modifier.method_data.supported_method.empty()) {
92 *error_message = "Must specify payment method identifier";
93 return false;
94 }
95
96 if (modifier.total) {
97 if (!ValidateShippingOptionOrPaymentItem(*modifier.total, total,
98 error_message))
99 return false;
100
101 if (modifier.total->amount->value[0] == '-') {
102 *error_message = "Total amount value should be non-negative";
103 return false;
104 }
105 }
106
107 if (modifier.additional_display_items.size()) {
108 if (!ValidateDisplayItems(modifier.additional_display_items, total,
109 error_message)) {
110 return false;
111 }
112 }
113 }
114 return true;
115 }
116
117 } // namespace
118
ValidatePaymentDetails(const PaymentDetails & details,std::string * error_message)119 bool ValidatePaymentDetails(const PaymentDetails& details,
120 std::string* error_message) {
121 if (details.total) {
122 if (!ValidateShippingOptionOrPaymentItem(*details.total, *details.total,
123 error_message)) {
124 return false;
125 }
126
127 if (details.total->amount->value[0] == '-') {
128 *error_message = "Total amount value should be non-negative";
129 return false;
130 }
131 }
132
133 if (details.display_items.size()) {
134 if (!ValidateDisplayItems(details.display_items, *details.total,
135 error_message))
136 return false;
137 }
138
139 if (details.shipping_options.size()) {
140 if (!ValidateShippingOptions(details.shipping_options, *details.total,
141 error_message))
142 return false;
143 }
144
145 if (details.modifiers.size()) {
146 if (!ValidatePaymentDetailsModifiers(details.modifiers, *details.total,
147 error_message))
148 return false;
149 }
150 if (!PaymentsValidators::IsValidErrorMsgFormat(details.error, error_message))
151 return false;
152 return true;
153 }
154
155 } // namespace payments
156