1 //
2 // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 #include "td/telegram/Payments.h"
8 
9 #include "td/telegram/AccessRights.h"
10 #include "td/telegram/ContactsManager.h"
11 #include "td/telegram/files/FileManager.h"
12 #include "td/telegram/files/FileType.h"
13 #include "td/telegram/Global.h"
14 #include "td/telegram/MessagesManager.h"
15 #include "td/telegram/misc.h"
16 #include "td/telegram/PasswordManager.h"
17 #include "td/telegram/ServerMessageId.h"
18 #include "td/telegram/Td.h"
19 #include "td/telegram/UpdatesManager.h"
20 
21 #include "td/utils/algorithm.h"
22 #include "td/utils/buffer.h"
23 #include "td/utils/common.h"
24 #include "td/utils/format.h"
25 #include "td/utils/HttpUrl.h"
26 #include "td/utils/JsonBuilder.h"
27 #include "td/utils/logging.h"
28 #include "td/utils/MimeType.h"
29 #include "td/utils/PathView.h"
30 #include "td/utils/Status.h"
31 
32 namespace td {
33 
34 class SetBotShippingAnswerQuery final : public Td::ResultHandler {
35   Promise<Unit> promise_;
36 
37  public:
SetBotShippingAnswerQuery(Promise<Unit> && promise)38   explicit SetBotShippingAnswerQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
39   }
40 
send(int64 shipping_query_id,const string & error_message,vector<tl_object_ptr<telegram_api::shippingOption>> && shipping_options)41   void send(int64 shipping_query_id, const string &error_message,
42             vector<tl_object_ptr<telegram_api::shippingOption>> &&shipping_options) {
43     int32 flags = 0;
44     if (!error_message.empty()) {
45       flags |= telegram_api::messages_setBotShippingResults::ERROR_MASK;
46     }
47     if (!shipping_options.empty()) {
48       flags |= telegram_api::messages_setBotShippingResults::SHIPPING_OPTIONS_MASK;
49     }
50     send_query(G()->net_query_creator().create(telegram_api::messages_setBotShippingResults(
51         flags, shipping_query_id, error_message, std::move(shipping_options))));
52   }
53 
on_result(BufferSlice packet)54   void on_result(BufferSlice packet) final {
55     auto result_ptr = fetch_result<telegram_api::messages_setBotShippingResults>(packet);
56     if (result_ptr.is_error()) {
57       return on_error(result_ptr.move_as_error());
58     }
59 
60     bool result = result_ptr.ok();
61     if (!result) {
62       LOG(INFO) << "Sending answer to a shipping query has failed";
63     }
64     promise_.set_value(Unit());
65   }
66 
on_error(Status status)67   void on_error(Status status) final {
68     promise_.set_error(std::move(status));
69   }
70 };
71 
72 class SetBotPreCheckoutAnswerQuery final : public Td::ResultHandler {
73   Promise<Unit> promise_;
74 
75  public:
SetBotPreCheckoutAnswerQuery(Promise<Unit> && promise)76   explicit SetBotPreCheckoutAnswerQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
77   }
78 
send(int64 pre_checkout_query_id,const string & error_message)79   void send(int64 pre_checkout_query_id, const string &error_message) {
80     int32 flags = 0;
81     if (!error_message.empty()) {
82       flags |= telegram_api::messages_setBotPrecheckoutResults::ERROR_MASK;
83     } else {
84       flags |= telegram_api::messages_setBotPrecheckoutResults::SUCCESS_MASK;
85     }
86 
87     send_query(G()->net_query_creator().create(telegram_api::messages_setBotPrecheckoutResults(
88         flags, false /*ignored*/, pre_checkout_query_id, error_message)));
89   }
90 
on_result(BufferSlice packet)91   void on_result(BufferSlice packet) final {
92     auto result_ptr = fetch_result<telegram_api::messages_setBotPrecheckoutResults>(packet);
93     if (result_ptr.is_error()) {
94       return on_error(result_ptr.move_as_error());
95     }
96 
97     bool result = result_ptr.ok();
98     if (!result) {
99       LOG(INFO) << "Sending answer to a pre-checkout query has failed";
100     }
101     promise_.set_value(Unit());
102   }
103 
on_error(Status status)104   void on_error(Status status) final {
105     promise_.set_error(std::move(status));
106   }
107 };
108 
convert_invoice(tl_object_ptr<telegram_api::invoice> invoice)109 static tl_object_ptr<td_api::invoice> convert_invoice(tl_object_ptr<telegram_api::invoice> invoice) {
110   CHECK(invoice != nullptr);
111 
112   vector<tl_object_ptr<td_api::labeledPricePart>> labeled_prices;
113   labeled_prices.reserve(invoice->prices_.size());
114   for (auto &labeled_price : invoice->prices_) {
115     labeled_prices.push_back(
116         make_tl_object<td_api::labeledPricePart>(std::move(labeled_price->label_), labeled_price->amount_));
117   }
118 
119   bool is_test = (invoice->flags_ & telegram_api::invoice::TEST_MASK) != 0;
120   bool need_name = (invoice->flags_ & telegram_api::invoice::NAME_REQUESTED_MASK) != 0;
121   bool need_phone_number = (invoice->flags_ & telegram_api::invoice::PHONE_REQUESTED_MASK) != 0;
122   bool need_email_address = (invoice->flags_ & telegram_api::invoice::EMAIL_REQUESTED_MASK) != 0;
123   bool need_shipping_address = (invoice->flags_ & telegram_api::invoice::SHIPPING_ADDRESS_REQUESTED_MASK) != 0;
124   bool send_phone_number_to_provider = (invoice->flags_ & telegram_api::invoice::PHONE_TO_PROVIDER_MASK) != 0;
125   bool send_email_address_to_provider = (invoice->flags_ & telegram_api::invoice::EMAIL_TO_PROVIDER_MASK) != 0;
126   bool is_flexible = (invoice->flags_ & telegram_api::invoice::FLEXIBLE_MASK) != 0;
127   if (send_phone_number_to_provider) {
128     need_phone_number = true;
129   }
130   if (send_email_address_to_provider) {
131     need_email_address = true;
132   }
133   if (is_flexible) {
134     need_shipping_address = true;
135   }
136 
137   return make_tl_object<td_api::invoice>(
138       std::move(invoice->currency_), std::move(labeled_prices), invoice->max_tip_amount_,
139       vector<int64>(invoice->suggested_tip_amounts_), is_test, need_name, need_phone_number, need_email_address,
140       need_shipping_address, send_phone_number_to_provider, send_email_address_to_provider, is_flexible);
141 }
142 
convert_payment_provider(const string & native_provider_name,tl_object_ptr<telegram_api::dataJSON> native_parameters)143 static tl_object_ptr<td_api::paymentsProviderStripe> convert_payment_provider(
144     const string &native_provider_name, tl_object_ptr<telegram_api::dataJSON> native_parameters) {
145   if (native_parameters == nullptr) {
146     return nullptr;
147   }
148 
149   if (native_provider_name == "stripe") {
150     string data = native_parameters->data_;
151     auto r_value = json_decode(data);
152     if (r_value.is_error()) {
153       LOG(ERROR) << "Can't parse JSON object \"" << native_parameters->data_ << "\": " << r_value.error();
154       return nullptr;
155     }
156 
157     auto value = r_value.move_as_ok();
158     if (value.type() != JsonValue::Type::Object) {
159       LOG(ERROR) << "Wrong JSON data \"" << native_parameters->data_ << '"';
160       return nullptr;
161     }
162 
163     auto r_need_country = get_json_object_bool_field(value.get_object(), "need_country", false);
164     auto r_need_postal_code = get_json_object_bool_field(value.get_object(), "need_zip", false);
165     auto r_need_cardholder_name = get_json_object_bool_field(value.get_object(), "need_cardholder_name", false);
166     auto r_publishable_key = get_json_object_string_field(value.get_object(), "publishable_key", false);
167     // TODO support "gpay_parameters":{"gateway":"stripe","stripe:publishableKey":"...","stripe:version":"..."}
168 
169     if (r_need_country.is_error() || r_need_postal_code.is_error() || r_need_cardholder_name.is_error() ||
170         r_publishable_key.is_error()) {
171       LOG(ERROR) << "Unsupported JSON data \"" << native_parameters->data_ << '"';
172       return nullptr;
173     }
174     if (value.get_object().size() != 5) {
175       LOG(ERROR) << "Unsupported JSON data \"" << native_parameters->data_ << '"';
176     }
177 
178     return make_tl_object<td_api::paymentsProviderStripe>(r_publishable_key.move_as_ok(), r_need_country.move_as_ok(),
179                                                           r_need_postal_code.move_as_ok(),
180                                                           r_need_cardholder_name.move_as_ok());
181   }
182 
183   return nullptr;
184 }
185 
convert_address(tl_object_ptr<telegram_api::postAddress> address)186 static tl_object_ptr<td_api::address> convert_address(tl_object_ptr<telegram_api::postAddress> address) {
187   if (address == nullptr) {
188     return nullptr;
189   }
190   return make_tl_object<td_api::address>(std::move(address->country_iso2_), std::move(address->state_),
191                                          std::move(address->city_), std::move(address->street_line1_),
192                                          std::move(address->street_line2_), std::move(address->post_code_));
193 }
194 
convert_address(tl_object_ptr<td_api::address> address)195 static tl_object_ptr<telegram_api::postAddress> convert_address(tl_object_ptr<td_api::address> address) {
196   if (address == nullptr) {
197     return nullptr;
198   }
199   return make_tl_object<telegram_api::postAddress>(std::move(address->street_line1_), std::move(address->street_line2_),
200                                                    std::move(address->city_), std::move(address->state_),
201                                                    std::move(address->country_code_), std::move(address->postal_code_));
202 }
203 
convert_order_info(tl_object_ptr<telegram_api::paymentRequestedInfo> order_info)204 static tl_object_ptr<td_api::orderInfo> convert_order_info(
205     tl_object_ptr<telegram_api::paymentRequestedInfo> order_info) {
206   if (order_info == nullptr) {
207     return nullptr;
208   }
209   return make_tl_object<td_api::orderInfo>(std::move(order_info->name_), std::move(order_info->phone_),
210                                            std::move(order_info->email_),
211                                            convert_address(std::move(order_info->shipping_address_)));
212 }
213 
convert_labeled_price(tl_object_ptr<telegram_api::labeledPrice> labeled_price)214 static tl_object_ptr<td_api::labeledPricePart> convert_labeled_price(
215     tl_object_ptr<telegram_api::labeledPrice> labeled_price) {
216   CHECK(labeled_price != nullptr);
217   return make_tl_object<td_api::labeledPricePart>(std::move(labeled_price->label_), labeled_price->amount_);
218 }
219 
convert_shipping_option(tl_object_ptr<telegram_api::shippingOption> shipping_option)220 static tl_object_ptr<td_api::shippingOption> convert_shipping_option(
221     tl_object_ptr<telegram_api::shippingOption> shipping_option) {
222   if (shipping_option == nullptr) {
223     return nullptr;
224   }
225 
226   return make_tl_object<td_api::shippingOption>(std::move(shipping_option->id_), std::move(shipping_option->title_),
227                                                 transform(std::move(shipping_option->prices_), convert_labeled_price));
228 }
229 
convert_order_info(tl_object_ptr<td_api::orderInfo> order_info)230 static tl_object_ptr<telegram_api::paymentRequestedInfo> convert_order_info(
231     tl_object_ptr<td_api::orderInfo> order_info) {
232   if (order_info == nullptr) {
233     return nullptr;
234   }
235   int32 flags = 0;
236   if (!order_info->name_.empty()) {
237     flags |= telegram_api::paymentRequestedInfo::NAME_MASK;
238   }
239   if (!order_info->phone_number_.empty()) {
240     flags |= telegram_api::paymentRequestedInfo::PHONE_MASK;
241   }
242   if (!order_info->email_address_.empty()) {
243     flags |= telegram_api::paymentRequestedInfo::EMAIL_MASK;
244   }
245   if (order_info->shipping_address_ != nullptr) {
246     flags |= telegram_api::paymentRequestedInfo::SHIPPING_ADDRESS_MASK;
247   }
248   return make_tl_object<telegram_api::paymentRequestedInfo>(
249       flags, std::move(order_info->name_), std::move(order_info->phone_number_), std::move(order_info->email_address_),
250       convert_address(std::move(order_info->shipping_address_)));
251 }
252 
convert_saved_credentials(tl_object_ptr<telegram_api::paymentSavedCredentialsCard> saved_credentials)253 static tl_object_ptr<td_api::savedCredentials> convert_saved_credentials(
254     tl_object_ptr<telegram_api::paymentSavedCredentialsCard> saved_credentials) {
255   if (saved_credentials == nullptr) {
256     return nullptr;
257   }
258   return make_tl_object<td_api::savedCredentials>(std::move(saved_credentials->id_),
259                                                   std::move(saved_credentials->title_));
260 }
261 
262 class GetPaymentFormQuery final : public Td::ResultHandler {
263   Promise<tl_object_ptr<td_api::paymentForm>> promise_;
264   DialogId dialog_id_;
265 
266  public:
GetPaymentFormQuery(Promise<tl_object_ptr<td_api::paymentForm>> && promise)267   explicit GetPaymentFormQuery(Promise<tl_object_ptr<td_api::paymentForm>> &&promise) : promise_(std::move(promise)) {
268   }
269 
send(DialogId dialog_id,ServerMessageId server_message_id,tl_object_ptr<telegram_api::dataJSON> && theme_parameters)270   void send(DialogId dialog_id, ServerMessageId server_message_id,
271             tl_object_ptr<telegram_api::dataJSON> &&theme_parameters) {
272     dialog_id_ = dialog_id;
273     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
274     if (input_peer == nullptr) {
275       return on_error(Status::Error(400, "Can't access the chat"));
276     }
277 
278     int32 flags = 0;
279     if (theme_parameters != nullptr) {
280       flags |= telegram_api::payments_getPaymentForm::THEME_PARAMS_MASK;
281     }
282     send_query(G()->net_query_creator().create(telegram_api::payments_getPaymentForm(
283         flags, std::move(input_peer), server_message_id.get(), std::move(theme_parameters))));
284   }
285 
on_result(BufferSlice packet)286   void on_result(BufferSlice packet) final {
287     auto result_ptr = fetch_result<telegram_api::payments_getPaymentForm>(packet);
288     if (result_ptr.is_error()) {
289       return on_error(result_ptr.move_as_error());
290     }
291 
292     auto payment_form = result_ptr.move_as_ok();
293     LOG(INFO) << "Receive result for GetPaymentFormQuery: " << to_string(payment_form);
294 
295     td_->contacts_manager_->on_get_users(std::move(payment_form->users_), "GetPaymentFormQuery");
296 
297     UserId payments_provider_user_id(payment_form->provider_id_);
298     if (!payments_provider_user_id.is_valid()) {
299       LOG(ERROR) << "Receive invalid payments provider " << payments_provider_user_id;
300       return on_error(Status::Error(500, "Receive invalid payments provider identifier"));
301     }
302     UserId seller_bot_user_id(payment_form->bot_id_);
303     if (!seller_bot_user_id.is_valid()) {
304       LOG(ERROR) << "Receive invalid seller " << seller_bot_user_id;
305       return on_error(Status::Error(500, "Receive invalid seller identifier"));
306     }
307     bool can_save_credentials = payment_form->can_save_credentials_;
308     bool need_password = payment_form->password_missing_;
309     promise_.set_value(make_tl_object<td_api::paymentForm>(
310         payment_form->form_id_, convert_invoice(std::move(payment_form->invoice_)), std::move(payment_form->url_),
311         td_->contacts_manager_->get_user_id_object(seller_bot_user_id, "paymentForm seller"),
312         td_->contacts_manager_->get_user_id_object(payments_provider_user_id, "paymentForm provider"),
313         convert_payment_provider(payment_form->native_provider_, std::move(payment_form->native_params_)),
314         convert_order_info(std::move(payment_form->saved_info_)),
315         convert_saved_credentials(std::move(payment_form->saved_credentials_)), can_save_credentials, need_password));
316   }
317 
on_error(Status status)318   void on_error(Status status) final {
319     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetPaymentFormQuery");
320     promise_.set_error(std::move(status));
321   }
322 };
323 
324 class ValidateRequestedInfoQuery final : public Td::ResultHandler {
325   Promise<tl_object_ptr<td_api::validatedOrderInfo>> promise_;
326   DialogId dialog_id_;
327 
328  public:
ValidateRequestedInfoQuery(Promise<tl_object_ptr<td_api::validatedOrderInfo>> && promise)329   explicit ValidateRequestedInfoQuery(Promise<tl_object_ptr<td_api::validatedOrderInfo>> &&promise)
330       : promise_(std::move(promise)) {
331   }
332 
send(DialogId dialog_id,ServerMessageId server_message_id,tl_object_ptr<telegram_api::paymentRequestedInfo> requested_info,bool allow_save)333   void send(DialogId dialog_id, ServerMessageId server_message_id,
334             tl_object_ptr<telegram_api::paymentRequestedInfo> requested_info, bool allow_save) {
335     dialog_id_ = dialog_id;
336     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
337     if (input_peer == nullptr) {
338       return on_error(Status::Error(400, "Can't access the chat"));
339     }
340 
341     int32 flags = 0;
342     if (allow_save) {
343       flags |= telegram_api::payments_validateRequestedInfo::SAVE_MASK;
344     }
345     if (requested_info == nullptr) {
346       requested_info = make_tl_object<telegram_api::paymentRequestedInfo>();
347       requested_info->flags_ = 0;
348     }
349     send_query(G()->net_query_creator().create(telegram_api::payments_validateRequestedInfo(
350         flags, false /*ignored*/, std::move(input_peer), server_message_id.get(), std::move(requested_info))));
351   }
352 
on_result(BufferSlice packet)353   void on_result(BufferSlice packet) final {
354     auto result_ptr = fetch_result<telegram_api::payments_validateRequestedInfo>(packet);
355     if (result_ptr.is_error()) {
356       return on_error(result_ptr.move_as_error());
357     }
358 
359     auto validated_order_info = result_ptr.move_as_ok();
360     LOG(INFO) << "Receive result for ValidateRequestedInfoQuery: " << to_string(validated_order_info);
361 
362     promise_.set_value(make_tl_object<td_api::validatedOrderInfo>(
363         std::move(validated_order_info->id_),
364         transform(std::move(validated_order_info->shipping_options_), convert_shipping_option)));
365   }
366 
on_error(Status status)367   void on_error(Status status) final {
368     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "ValidateRequestedInfoQuery");
369     promise_.set_error(std::move(status));
370   }
371 };
372 
373 class SendPaymentFormQuery final : public Td::ResultHandler {
374   Promise<tl_object_ptr<td_api::paymentResult>> promise_;
375   DialogId dialog_id_;
376 
377  public:
SendPaymentFormQuery(Promise<tl_object_ptr<td_api::paymentResult>> && promise)378   explicit SendPaymentFormQuery(Promise<tl_object_ptr<td_api::paymentResult>> &&promise)
379       : promise_(std::move(promise)) {
380   }
381 
send(DialogId dialog_id,ServerMessageId server_message_id,int64 payment_form_id,const string & order_info_id,const string & shipping_option_id,tl_object_ptr<telegram_api::InputPaymentCredentials> input_credentials,int64 tip_amount)382   void send(DialogId dialog_id, ServerMessageId server_message_id, int64 payment_form_id, const string &order_info_id,
383             const string &shipping_option_id, tl_object_ptr<telegram_api::InputPaymentCredentials> input_credentials,
384             int64 tip_amount) {
385     CHECK(input_credentials != nullptr);
386 
387     dialog_id_ = dialog_id;
388     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
389     if (input_peer == nullptr) {
390       return on_error(Status::Error(400, "Can't access the chat"));
391     }
392 
393     int32 flags = 0;
394     if (!order_info_id.empty()) {
395       flags |= telegram_api::payments_sendPaymentForm::REQUESTED_INFO_ID_MASK;
396     }
397     if (!shipping_option_id.empty()) {
398       flags |= telegram_api::payments_sendPaymentForm::SHIPPING_OPTION_ID_MASK;
399     }
400     if (tip_amount != 0) {
401       flags |= telegram_api::payments_sendPaymentForm::TIP_AMOUNT_MASK;
402     }
403     send_query(G()->net_query_creator().create(telegram_api::payments_sendPaymentForm(
404         flags, payment_form_id, std::move(input_peer), server_message_id.get(), order_info_id, shipping_option_id,
405         std::move(input_credentials), tip_amount)));
406   }
407 
on_result(BufferSlice packet)408   void on_result(BufferSlice packet) final {
409     auto result_ptr = fetch_result<telegram_api::payments_sendPaymentForm>(packet);
410     if (result_ptr.is_error()) {
411       return on_error(result_ptr.move_as_error());
412     }
413 
414     auto payment_result = result_ptr.move_as_ok();
415     LOG(INFO) << "Receive result for SendPaymentFormQuery: " << to_string(payment_result);
416 
417     switch (payment_result->get_id()) {
418       case telegram_api::payments_paymentResult::ID: {
419         auto result = move_tl_object_as<telegram_api::payments_paymentResult>(payment_result);
420         td_->updates_manager_->on_get_updates(
421             std::move(result->updates_), PromiseCreator::lambda([promise = std::move(promise_)](Unit) mutable {
422               promise.set_value(make_tl_object<td_api::paymentResult>(true, string()));
423             }));
424         return;
425       }
426       case telegram_api::payments_paymentVerificationNeeded::ID: {
427         auto result = move_tl_object_as<telegram_api::payments_paymentVerificationNeeded>(payment_result);
428         promise_.set_value(make_tl_object<td_api::paymentResult>(false, std::move(result->url_)));
429         return;
430       }
431       default:
432         UNREACHABLE();
433     }
434   }
435 
on_error(Status status)436   void on_error(Status status) final {
437     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "SendPaymentFormQuery");
438     promise_.set_error(std::move(status));
439   }
440 };
441 
442 class GetPaymentReceiptQuery final : public Td::ResultHandler {
443   Promise<tl_object_ptr<td_api::paymentReceipt>> promise_;
444   DialogId dialog_id_;
445 
446  public:
GetPaymentReceiptQuery(Promise<tl_object_ptr<td_api::paymentReceipt>> && promise)447   explicit GetPaymentReceiptQuery(Promise<tl_object_ptr<td_api::paymentReceipt>> &&promise)
448       : promise_(std::move(promise)) {
449   }
450 
send(DialogId dialog_id,ServerMessageId server_message_id)451   void send(DialogId dialog_id, ServerMessageId server_message_id) {
452     dialog_id_ = dialog_id;
453     auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
454     if (input_peer == nullptr) {
455       return on_error(Status::Error(400, "Can't access the chat"));
456     }
457 
458     send_query(G()->net_query_creator().create(
459         telegram_api::payments_getPaymentReceipt(std::move(input_peer), server_message_id.get())));
460   }
461 
on_result(BufferSlice packet)462   void on_result(BufferSlice packet) final {
463     auto result_ptr = fetch_result<telegram_api::payments_getPaymentReceipt>(packet);
464     if (result_ptr.is_error()) {
465       return on_error(result_ptr.move_as_error());
466     }
467 
468     auto payment_receipt = result_ptr.move_as_ok();
469     LOG(INFO) << "Receive result for GetPaymentReceiptQuery: " << to_string(payment_receipt);
470 
471     td_->contacts_manager_->on_get_users(std::move(payment_receipt->users_), "GetPaymentReceiptQuery");
472 
473     UserId payments_provider_user_id(payment_receipt->provider_id_);
474     if (!payments_provider_user_id.is_valid()) {
475       LOG(ERROR) << "Receive invalid payments provider " << payments_provider_user_id;
476       return on_error(Status::Error(500, "Receive invalid payments provider identifier"));
477     }
478     UserId seller_bot_user_id(payment_receipt->bot_id_);
479     if (!seller_bot_user_id.is_valid()) {
480       LOG(ERROR) << "Receive invalid seller " << seller_bot_user_id;
481       return on_error(Status::Error(500, "Receive invalid seller identifier"));
482     }
483     auto photo = get_web_document_photo(td_->file_manager_.get(), std::move(payment_receipt->photo_), dialog_id_);
484 
485     promise_.set_value(make_tl_object<td_api::paymentReceipt>(
486         payment_receipt->title_, payment_receipt->description_, get_photo_object(td_->file_manager_.get(), photo),
487         payment_receipt->date_, td_->contacts_manager_->get_user_id_object(seller_bot_user_id, "paymentReceipt seller"),
488         td_->contacts_manager_->get_user_id_object(payments_provider_user_id, "paymentReceipt provider"),
489         convert_invoice(std::move(payment_receipt->invoice_)), convert_order_info(std::move(payment_receipt->info_)),
490         convert_shipping_option(std::move(payment_receipt->shipping_)), std::move(payment_receipt->credentials_title_),
491         payment_receipt->tip_amount_));
492   }
493 
on_error(Status status)494   void on_error(Status status) final {
495     td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetPaymentReceiptQuery");
496     promise_.set_error(std::move(status));
497   }
498 };
499 
500 class GetSavedInfoQuery final : public Td::ResultHandler {
501   Promise<tl_object_ptr<td_api::orderInfo>> promise_;
502 
503  public:
GetSavedInfoQuery(Promise<tl_object_ptr<td_api::orderInfo>> && promise)504   explicit GetSavedInfoQuery(Promise<tl_object_ptr<td_api::orderInfo>> &&promise) : promise_(std::move(promise)) {
505   }
506 
send()507   void send() {
508     send_query(G()->net_query_creator().create(telegram_api::payments_getSavedInfo()));
509   }
510 
on_result(BufferSlice packet)511   void on_result(BufferSlice packet) final {
512     auto result_ptr = fetch_result<telegram_api::payments_getSavedInfo>(packet);
513     if (result_ptr.is_error()) {
514       return on_error(result_ptr.move_as_error());
515     }
516 
517     auto saved_info = result_ptr.move_as_ok();
518     LOG(INFO) << "Receive result for GetSavedInfoQuery: " << to_string(saved_info);
519     promise_.set_value(convert_order_info(std::move(saved_info->saved_info_)));
520   }
521 
on_error(Status status)522   void on_error(Status status) final {
523     promise_.set_error(std::move(status));
524   }
525 };
526 
527 class ClearSavedInfoQuery final : public Td::ResultHandler {
528   Promise<Unit> promise_;
529 
530  public:
ClearSavedInfoQuery(Promise<Unit> && promise)531   explicit ClearSavedInfoQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
532   }
533 
send(bool clear_credentials,bool clear_order_info)534   void send(bool clear_credentials, bool clear_order_info) {
535     CHECK(clear_credentials || clear_order_info);
536     int32 flags = 0;
537     if (clear_credentials) {
538       flags |= telegram_api::payments_clearSavedInfo::CREDENTIALS_MASK;
539     }
540     if (clear_order_info) {
541       flags |= telegram_api::payments_clearSavedInfo::INFO_MASK;
542     }
543     send_query(G()->net_query_creator().create(
544         telegram_api::payments_clearSavedInfo(flags, false /*ignored*/, false /*ignored*/)));
545   }
546 
on_result(BufferSlice packet)547   void on_result(BufferSlice packet) final {
548     auto result_ptr = fetch_result<telegram_api::payments_clearSavedInfo>(packet);
549     if (result_ptr.is_error()) {
550       return on_error(result_ptr.move_as_error());
551     }
552 
553     promise_.set_value(Unit());
554   }
555 
on_error(Status status)556   void on_error(Status status) final {
557     promise_.set_error(std::move(status));
558   }
559 };
560 
561 class GetBankCardInfoQuery final : public Td::ResultHandler {
562   Promise<td_api::object_ptr<td_api::bankCardInfo>> promise_;
563 
564  public:
GetBankCardInfoQuery(Promise<td_api::object_ptr<td_api::bankCardInfo>> && promise)565   explicit GetBankCardInfoQuery(Promise<td_api::object_ptr<td_api::bankCardInfo>> &&promise)
566       : promise_(std::move(promise)) {
567   }
568 
send(const string & bank_card_number)569   void send(const string &bank_card_number) {
570     send_query(G()->net_query_creator().create(telegram_api::payments_getBankCardData(bank_card_number),
571                                                G()->get_webfile_dc_id()));
572   }
573 
on_result(BufferSlice packet)574   void on_result(BufferSlice packet) final {
575     auto result_ptr = fetch_result<telegram_api::payments_getBankCardData>(packet);
576     if (result_ptr.is_error()) {
577       return on_error(result_ptr.move_as_error());
578     }
579 
580     auto response = result_ptr.move_as_ok();
581     auto actions = transform(response->open_urls_, [](auto &open_url) {
582       return td_api::make_object<td_api::bankCardActionOpenUrl>(open_url->name_, open_url->url_);
583     });
584     promise_.set_value(td_api::make_object<td_api::bankCardInfo>(response->title_, std::move(actions)));
585   }
586 
on_error(Status status)587   void on_error(Status status) final {
588     promise_.set_error(std::move(status));
589   }
590 };
591 
operator ==(const LabeledPricePart & lhs,const LabeledPricePart & rhs)592 bool operator==(const LabeledPricePart &lhs, const LabeledPricePart &rhs) {
593   return lhs.label == rhs.label && lhs.amount == rhs.amount;
594 }
595 
operator !=(const LabeledPricePart & lhs,const LabeledPricePart & rhs)596 bool operator!=(const LabeledPricePart &lhs, const LabeledPricePart &rhs) {
597   return !(lhs == rhs);
598 }
599 
operator <<(StringBuilder & string_builder,const LabeledPricePart & labeled_price_part)600 StringBuilder &operator<<(StringBuilder &string_builder, const LabeledPricePart &labeled_price_part) {
601   return string_builder << "[" << labeled_price_part.label << ": " << labeled_price_part.amount << "]";
602 }
603 
operator ==(const Invoice & lhs,const Invoice & rhs)604 bool operator==(const Invoice &lhs, const Invoice &rhs) {
605   return lhs.is_test == rhs.is_test && lhs.need_name == rhs.need_name &&
606          lhs.need_phone_number == rhs.need_phone_number && lhs.need_email_address == rhs.need_email_address &&
607          lhs.need_shipping_address == rhs.need_shipping_address &&
608          lhs.send_phone_number_to_provider == rhs.send_phone_number_to_provider &&
609          lhs.send_email_address_to_provider == rhs.send_email_address_to_provider &&
610          lhs.is_flexible == rhs.is_flexible && lhs.currency == rhs.currency && lhs.price_parts == rhs.price_parts &&
611          lhs.max_tip_amount == rhs.max_tip_amount && lhs.suggested_tip_amounts == rhs.suggested_tip_amounts;
612 }
613 
operator !=(const Invoice & lhs,const Invoice & rhs)614 bool operator!=(const Invoice &lhs, const Invoice &rhs) {
615   return !(lhs == rhs);
616 }
617 
operator <<(StringBuilder & string_builder,const Invoice & invoice)618 StringBuilder &operator<<(StringBuilder &string_builder, const Invoice &invoice) {
619   return string_builder << "[" << (invoice.is_flexible ? "Flexible" : "") << (invoice.is_test ? "Test" : "")
620                         << "Invoice" << (invoice.need_name ? ", needs name" : "")
621                         << (invoice.need_phone_number ? ", needs phone number" : "")
622                         << (invoice.need_email_address ? ", needs email address" : "")
623                         << (invoice.need_shipping_address ? ", needs shipping address" : "")
624                         << (invoice.send_phone_number_to_provider ? ", sends phone number to provider" : "")
625                         << (invoice.send_email_address_to_provider ? ", sends email address to provider" : "") << " in "
626                         << invoice.currency << " with price parts " << format::as_array(invoice.price_parts)
627                         << " and suggested tip amounts " << invoice.suggested_tip_amounts << " up to "
628                         << invoice.max_tip_amount << "]";
629 }
630 
operator ==(const InputInvoice & lhs,const InputInvoice & rhs)631 bool operator==(const InputInvoice &lhs, const InputInvoice &rhs) {
632   return lhs.title == rhs.title && lhs.description == rhs.description && lhs.photo == rhs.photo &&
633          lhs.start_parameter == rhs.start_parameter && lhs.invoice == rhs.invoice &&
634          lhs.total_amount == rhs.total_amount && lhs.receipt_message_id == rhs.receipt_message_id &&
635          lhs.payload == rhs.payload && lhs.provider_token == rhs.provider_token &&
636          lhs.provider_data == rhs.provider_data;
637 }
638 
operator !=(const InputInvoice & lhs,const InputInvoice & rhs)639 bool operator!=(const InputInvoice &lhs, const InputInvoice &rhs) {
640   return !(lhs == rhs);
641 }
642 
get_input_invoice(tl_object_ptr<telegram_api::messageMediaInvoice> && message_invoice,Td * td,DialogId owner_dialog_id)643 InputInvoice get_input_invoice(tl_object_ptr<telegram_api::messageMediaInvoice> &&message_invoice, Td *td,
644                                DialogId owner_dialog_id) {
645   InputInvoice result;
646   result.title = std::move(message_invoice->title_);
647   result.description = std::move(message_invoice->description_);
648   result.photo = get_web_document_photo(td->file_manager_.get(), std::move(message_invoice->photo_), owner_dialog_id);
649   result.start_parameter = std::move(message_invoice->start_param_);
650   result.invoice.currency = std::move(message_invoice->currency_);
651   result.invoice.is_test = message_invoice->test_;
652   result.invoice.need_shipping_address = message_invoice->shipping_address_requested_;
653   // result.payload = string();
654   // result.provider_token = string();
655   // result.provider_data = string();
656   result.total_amount = message_invoice->total_amount_;
657   if ((message_invoice->flags_ & telegram_api::messageMediaInvoice::RECEIPT_MSG_ID_MASK) != 0) {
658     result.receipt_message_id = MessageId(ServerMessageId(message_invoice->receipt_msg_id_));
659     if (!result.receipt_message_id.is_valid()) {
660       LOG(ERROR) << "Receive as receipt message " << result.receipt_message_id << " in " << owner_dialog_id;
661       result.receipt_message_id = MessageId();
662     }
663   }
664   return result;
665 }
666 
get_input_invoice(tl_object_ptr<telegram_api::botInlineMessageMediaInvoice> && message_invoice,Td * td,DialogId owner_dialog_id)667 InputInvoice get_input_invoice(tl_object_ptr<telegram_api::botInlineMessageMediaInvoice> &&message_invoice, Td *td,
668                                DialogId owner_dialog_id) {
669   InputInvoice result;
670   result.title = std::move(message_invoice->title_);
671   result.description = std::move(message_invoice->description_);
672   result.photo = get_web_document_photo(td->file_manager_.get(), std::move(message_invoice->photo_), owner_dialog_id);
673   // result.start_parameter = string();
674   result.invoice.currency = std::move(message_invoice->currency_);
675   result.invoice.is_test = message_invoice->test_;
676   result.invoice.need_shipping_address = message_invoice->shipping_address_requested_;
677   // result.payload = string();
678   // result.provider_token = string();
679   // result.provider_data = string();
680   result.total_amount = message_invoice->total_amount_;
681   // result.receipt_message_id = MessageId();
682   return result;
683 }
684 
process_input_message_invoice(td_api::object_ptr<td_api::InputMessageContent> && input_message_content,Td * td)685 Result<InputInvoice> process_input_message_invoice(
686     td_api::object_ptr<td_api::InputMessageContent> &&input_message_content, Td *td) {
687   CHECK(input_message_content != nullptr);
688   CHECK(input_message_content->get_id() == td_api::inputMessageInvoice::ID);
689   auto input_invoice = move_tl_object_as<td_api::inputMessageInvoice>(input_message_content);
690   if (input_invoice->invoice_ == nullptr) {
691     return Status::Error(400, "Invoice must be non-empty");
692   }
693 
694   if (!clean_input_string(input_invoice->title_)) {
695     return Status::Error(400, "Invoice title must be encoded in UTF-8");
696   }
697   if (!clean_input_string(input_invoice->description_)) {
698     return Status::Error(400, "Invoice description must be encoded in UTF-8");
699   }
700   if (!clean_input_string(input_invoice->photo_url_)) {
701     return Status::Error(400, "Invoice photo URL must be encoded in UTF-8");
702   }
703   if (!clean_input_string(input_invoice->start_parameter_)) {
704     return Status::Error(400, "Invoice bot start parameter must be encoded in UTF-8");
705   }
706   if (!clean_input_string(input_invoice->provider_token_)) {
707     return Status::Error(400, "Invoice provider token must be encoded in UTF-8");
708   }
709   if (!clean_input_string(input_invoice->provider_data_)) {
710     return Status::Error(400, "Invoice provider data must be encoded in UTF-8");
711   }
712   if (!clean_input_string(input_invoice->invoice_->currency_)) {
713     return Status::Error(400, "Invoice currency must be encoded in UTF-8");
714   }
715 
716   InputInvoice result;
717   result.title = std::move(input_invoice->title_);
718   result.description = std::move(input_invoice->description_);
719 
720   auto r_http_url = parse_url(input_invoice->photo_url_);
721   if (r_http_url.is_error()) {
722     if (!input_invoice->photo_url_.empty()) {
723       LOG(INFO) << "Can't register url " << input_invoice->photo_url_;
724     }
725   } else {
726     auto url = r_http_url.ok().get_url();
727     auto r_invoice_file_id = td->file_manager_->from_persistent_id(url, FileType::Temp);
728     if (r_invoice_file_id.is_error()) {
729       LOG(INFO) << "Can't register url " << url;
730     } else {
731       auto invoice_file_id = r_invoice_file_id.move_as_ok();
732 
733       PhotoSize s;
734       s.type = 'n';
735       s.dimensions =
736           get_dimensions(input_invoice->photo_width_, input_invoice->photo_height_, "process_input_message_invoice");
737       s.size = input_invoice->photo_size_;  // TODO use invoice_file_id size
738       s.file_id = invoice_file_id;
739 
740       result.photo.id = 0;
741       result.photo.photos.push_back(s);
742     }
743   }
744   result.start_parameter = std::move(input_invoice->start_parameter_);
745 
746   result.invoice.currency = std::move(input_invoice->invoice_->currency_);
747   result.invoice.price_parts.reserve(input_invoice->invoice_->price_parts_.size());
748   int64 total_amount = 0;
749   const int64 MAX_AMOUNT = 9999'9999'9999;
750   for (auto &price : input_invoice->invoice_->price_parts_) {
751     if (!clean_input_string(price->label_)) {
752       return Status::Error(400, "Invoice price label must be encoded in UTF-8");
753     }
754     result.invoice.price_parts.emplace_back(std::move(price->label_), price->amount_);
755     if (price->amount_ < -MAX_AMOUNT || price->amount_ > MAX_AMOUNT) {
756       return Status::Error(400, "Too big amount of the currency specified");
757     }
758     total_amount += price->amount_;
759   }
760   if (total_amount <= 0) {
761     return Status::Error(400, "Total price must be positive");
762   }
763   if (total_amount > MAX_AMOUNT) {
764     return Status::Error(400, "Total price is too big");
765   }
766   result.total_amount = total_amount;
767 
768   if (input_invoice->invoice_->max_tip_amount_ < 0 || input_invoice->invoice_->max_tip_amount_ > MAX_AMOUNT) {
769     return Status::Error(400, "Invalid max_tip_amount of the currency specified");
770   }
771   for (auto tip_amount : input_invoice->invoice_->suggested_tip_amounts_) {
772     if (tip_amount <= 0) {
773       return Status::Error(400, "Suggested tip amount must be positive");
774     }
775     if (tip_amount > input_invoice->invoice_->max_tip_amount_) {
776       return Status::Error(400, "Suggested tip amount can't be bigger than max_tip_amount");
777     }
778   }
779   if (input_invoice->invoice_->suggested_tip_amounts_.size() > 4) {
780     return Status::Error(400, "There can be at most 4 suggested tip amounts");
781   }
782 
783   result.invoice.max_tip_amount = input_invoice->invoice_->max_tip_amount_;
784   result.invoice.suggested_tip_amounts = std::move(input_invoice->invoice_->suggested_tip_amounts_);
785   result.invoice.is_test = input_invoice->invoice_->is_test_;
786   result.invoice.need_name = input_invoice->invoice_->need_name_;
787   result.invoice.need_phone_number = input_invoice->invoice_->need_phone_number_;
788   result.invoice.need_email_address = input_invoice->invoice_->need_email_address_;
789   result.invoice.need_shipping_address = input_invoice->invoice_->need_shipping_address_;
790   result.invoice.send_phone_number_to_provider = input_invoice->invoice_->send_phone_number_to_provider_;
791   result.invoice.send_email_address_to_provider = input_invoice->invoice_->send_email_address_to_provider_;
792   result.invoice.is_flexible = input_invoice->invoice_->is_flexible_;
793   if (result.invoice.send_phone_number_to_provider) {
794     result.invoice.need_phone_number = true;
795   }
796   if (result.invoice.send_email_address_to_provider) {
797     result.invoice.need_email_address = true;
798   }
799   if (result.invoice.is_flexible) {
800     result.invoice.need_shipping_address = true;
801   }
802 
803   result.payload = std::move(input_invoice->payload_);
804   result.provider_token = std::move(input_invoice->provider_token_);
805   result.provider_data = std::move(input_invoice->provider_data_);
806   return result;
807 }
808 
get_message_invoice_object(const InputInvoice & input_invoice,Td * td)809 tl_object_ptr<td_api::messageInvoice> get_message_invoice_object(const InputInvoice &input_invoice, Td *td) {
810   return make_tl_object<td_api::messageInvoice>(
811       input_invoice.title, input_invoice.description, get_photo_object(td->file_manager_.get(), input_invoice.photo),
812       input_invoice.invoice.currency, input_invoice.total_amount, input_invoice.start_parameter,
813       input_invoice.invoice.is_test, input_invoice.invoice.need_shipping_address,
814       input_invoice.receipt_message_id.get());
815 }
816 
get_input_invoice(const Invoice & invoice)817 static tl_object_ptr<telegram_api::invoice> get_input_invoice(const Invoice &invoice) {
818   int32 flags = 0;
819   if (invoice.is_test) {
820     flags |= telegram_api::invoice::TEST_MASK;
821   }
822   if (invoice.need_name) {
823     flags |= telegram_api::invoice::NAME_REQUESTED_MASK;
824   }
825   if (invoice.need_phone_number) {
826     flags |= telegram_api::invoice::PHONE_REQUESTED_MASK;
827   }
828   if (invoice.need_email_address) {
829     flags |= telegram_api::invoice::EMAIL_REQUESTED_MASK;
830   }
831   if (invoice.need_shipping_address) {
832     flags |= telegram_api::invoice::SHIPPING_ADDRESS_REQUESTED_MASK;
833   }
834   if (invoice.send_phone_number_to_provider) {
835     flags |= telegram_api::invoice::PHONE_TO_PROVIDER_MASK;
836   }
837   if (invoice.send_email_address_to_provider) {
838     flags |= telegram_api::invoice::EMAIL_TO_PROVIDER_MASK;
839   }
840   if (invoice.is_flexible) {
841     flags |= telegram_api::invoice::FLEXIBLE_MASK;
842   }
843   if (invoice.max_tip_amount != 0) {
844     flags |= telegram_api::invoice::MAX_TIP_AMOUNT_MASK;
845   }
846 
847   auto prices = transform(invoice.price_parts, [](const LabeledPricePart &price) {
848     return telegram_api::make_object<telegram_api::labeledPrice>(price.label, price.amount);
849   });
850   return make_tl_object<telegram_api::invoice>(
851       flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/,
852       false /*ignored*/, false /*ignored*/, false /*ignored*/, invoice.currency, std::move(prices),
853       invoice.max_tip_amount, vector<int64>(invoice.suggested_tip_amounts));
854 }
855 
get_input_web_document(const FileManager * file_manager,const Photo & photo)856 static tl_object_ptr<telegram_api::inputWebDocument> get_input_web_document(const FileManager *file_manager,
857                                                                             const Photo &photo) {
858   if (photo.is_empty()) {
859     return nullptr;
860   }
861 
862   CHECK(photo.photos.size() == 1);
863   const PhotoSize &size = photo.photos[0];
864   CHECK(size.file_id.is_valid());
865 
866   vector<tl_object_ptr<telegram_api::DocumentAttribute>> attributes;
867   if (size.dimensions.width != 0 && size.dimensions.height != 0) {
868     attributes.push_back(
869         make_tl_object<telegram_api::documentAttributeImageSize>(size.dimensions.width, size.dimensions.height));
870   }
871 
872   auto file_view = file_manager->get_file_view(size.file_id);
873   CHECK(file_view.has_url());
874 
875   auto file_name = get_url_file_name(file_view.url());
876   return make_tl_object<telegram_api::inputWebDocument>(
877       file_view.url(), size.size, MimeType::from_extension(PathView(file_name).extension(), "image/jpeg"),
878       std::move(attributes));
879 }
880 
get_input_media_invoice(const InputInvoice & input_invoice,Td * td)881 tl_object_ptr<telegram_api::inputMediaInvoice> get_input_media_invoice(const InputInvoice &input_invoice, Td *td) {
882   int32 flags = 0;
883   if (!input_invoice.start_parameter.empty()) {
884     flags |= telegram_api::inputMediaInvoice::START_PARAM_MASK;
885   }
886   auto input_web_document = get_input_web_document(td->file_manager_.get(), input_invoice.photo);
887   if (input_web_document != nullptr) {
888     flags |= telegram_api::inputMediaInvoice::PHOTO_MASK;
889   }
890 
891   return make_tl_object<telegram_api::inputMediaInvoice>(
892       flags, input_invoice.title, input_invoice.description, std::move(input_web_document),
893       get_input_invoice(input_invoice.invoice), BufferSlice(input_invoice.payload), input_invoice.provider_token,
894       telegram_api::make_object<telegram_api::dataJSON>(
895           input_invoice.provider_data.empty() ? "null" : input_invoice.provider_data),
896       input_invoice.start_parameter);
897 }
898 
get_input_bot_inline_message_media_invoice(const InputInvoice & input_invoice,tl_object_ptr<telegram_api::ReplyMarkup> && reply_markup,Td * td)899 tl_object_ptr<telegram_api::inputBotInlineMessageMediaInvoice> get_input_bot_inline_message_media_invoice(
900     const InputInvoice &input_invoice, tl_object_ptr<telegram_api::ReplyMarkup> &&reply_markup, Td *td) {
901   int32 flags = 0;
902   if (reply_markup != nullptr) {
903     flags |= telegram_api::inputBotInlineMessageMediaInvoice::REPLY_MARKUP_MASK;
904   }
905   auto input_web_document = get_input_web_document(td->file_manager_.get(), input_invoice.photo);
906   if (input_web_document != nullptr) {
907     flags |= telegram_api::inputBotInlineMessageMediaInvoice::PHOTO_MASK;
908   }
909   return make_tl_object<telegram_api::inputBotInlineMessageMediaInvoice>(
910       flags, input_invoice.title, input_invoice.description, std::move(input_web_document),
911       get_input_invoice(input_invoice.invoice), BufferSlice(input_invoice.payload), input_invoice.provider_token,
912       telegram_api::make_object<telegram_api::dataJSON>(
913           input_invoice.provider_data.empty() ? "null" : input_invoice.provider_data),
914       std::move(reply_markup));
915 }
916 
get_input_invoice_file_ids(const InputInvoice & input_invoice)917 vector<FileId> get_input_invoice_file_ids(const InputInvoice &input_invoice) {
918   return photo_get_file_ids(input_invoice.photo);
919 }
920 
operator ==(const Address & lhs,const Address & rhs)921 bool operator==(const Address &lhs, const Address &rhs) {
922   return lhs.country_code == rhs.country_code && lhs.state == rhs.state && lhs.city == rhs.city &&
923          lhs.street_line1 == rhs.street_line1 && lhs.street_line2 == rhs.street_line2 &&
924          lhs.postal_code == rhs.postal_code;
925 }
926 
operator !=(const Address & lhs,const Address & rhs)927 bool operator!=(const Address &lhs, const Address &rhs) {
928   return !(lhs == rhs);
929 }
930 
operator <<(StringBuilder & string_builder,const Address & address)931 StringBuilder &operator<<(StringBuilder &string_builder, const Address &address) {
932   return string_builder << "[Address " << tag("country_code", address.country_code) << tag("state", address.state)
933                         << tag("city", address.city) << tag("street_line1", address.street_line1)
934                         << tag("street_line2", address.street_line2) << tag("postal_code", address.postal_code) << "]";
935 }
936 
get_address(tl_object_ptr<telegram_api::postAddress> && address)937 unique_ptr<Address> get_address(tl_object_ptr<telegram_api::postAddress> &&address) {
938   if (address == nullptr) {
939     return nullptr;
940   }
941   return td::make_unique<Address>(std::move(address->country_iso2_), std::move(address->state_),
942                                   std::move(address->city_), std::move(address->street_line1_),
943                                   std::move(address->street_line2_), std::move(address->post_code_));
944 }
945 
is_capital_alpha(char c)946 static bool is_capital_alpha(char c) {
947   return 'A' <= c && c <= 'Z';
948 }
949 
check_country_code(string & country_code)950 Status check_country_code(string &country_code) {
951   if (!clean_input_string(country_code)) {
952     return Status::Error(400, "Country code must be encoded in UTF-8");
953   }
954   if (country_code.size() != 2 || !is_capital_alpha(country_code[0]) || !is_capital_alpha(country_code[1])) {
955     return Status::Error(400, "Wrong country code specified");
956   }
957   return Status::OK();
958 }
959 
check_state(string & state)960 static Status check_state(string &state) {
961   if (!clean_input_string(state)) {
962     return Status::Error(400, "State must be encoded in UTF-8");
963   }
964   return Status::OK();
965 }
966 
check_city(string & city)967 static Status check_city(string &city) {
968   if (!clean_input_string(city)) {
969     return Status::Error(400, "City must be encoded in UTF-8");
970   }
971   return Status::OK();
972 }
973 
check_street_line(string & street_line)974 static Status check_street_line(string &street_line) {
975   if (!clean_input_string(street_line)) {
976     return Status::Error(400, "Street line must be encoded in UTF-8");
977   }
978   return Status::OK();
979 }
980 
check_postal_code(string & postal_code)981 static Status check_postal_code(string &postal_code) {
982   if (!clean_input_string(postal_code)) {
983     return Status::Error(400, "Postal code must be encoded in UTF-8");
984   }
985   return Status::OK();
986 }
987 
get_address(td_api::object_ptr<td_api::address> && address)988 Result<Address> get_address(td_api::object_ptr<td_api::address> &&address) {
989   if (address == nullptr) {
990     return Status::Error(400, "Address must be non-empty");
991   }
992   TRY_STATUS(check_country_code(address->country_code_));
993   TRY_STATUS(check_state(address->state_));
994   TRY_STATUS(check_city(address->city_));
995   TRY_STATUS(check_street_line(address->street_line1_));
996   TRY_STATUS(check_street_line(address->street_line2_));
997   TRY_STATUS(check_postal_code(address->postal_code_));
998 
999   return Address(std::move(address->country_code_), std::move(address->state_), std::move(address->city_),
1000                  std::move(address->street_line1_), std::move(address->street_line2_),
1001                  std::move(address->postal_code_));
1002 }
1003 
get_address_object(const unique_ptr<Address> & address)1004 tl_object_ptr<td_api::address> get_address_object(const unique_ptr<Address> &address) {
1005   if (address == nullptr) {
1006     return nullptr;
1007   }
1008   return get_address_object(*address);
1009 }
1010 
get_address_object(const Address & address)1011 tl_object_ptr<td_api::address> get_address_object(const Address &address) {
1012   return make_tl_object<td_api::address>(address.country_code, address.state, address.city, address.street_line1,
1013                                          address.street_line2, address.postal_code);
1014 }
1015 
address_to_json(const Address & address)1016 string address_to_json(const Address &address) {
1017   return json_encode<std::string>(json_object([&](auto &o) {
1018     o("country_code", address.country_code);
1019     o("state", address.state);
1020     o("city", address.city);
1021     o("street_line1", address.street_line1);
1022     o("street_line2", address.street_line2);
1023     o("post_code", address.postal_code);
1024   }));
1025 }
1026 
address_from_json(Slice json)1027 Result<Address> address_from_json(Slice json) {
1028   auto json_copy = json.str();
1029   auto r_value = json_decode(json_copy);
1030   if (r_value.is_error()) {
1031     return Status::Error(400, "Can't parse address JSON object");
1032   }
1033 
1034   auto value = r_value.move_as_ok();
1035   if (value.type() != JsonValue::Type::Object) {
1036     return Status::Error(400, "Address must be an Object");
1037   }
1038 
1039   auto &object = value.get_object();
1040   TRY_RESULT(country_code, get_json_object_string_field(object, "country_code", true));
1041   TRY_RESULT(state, get_json_object_string_field(object, "state", true));
1042   TRY_RESULT(city, get_json_object_string_field(object, "city", true));
1043   TRY_RESULT(street_line1, get_json_object_string_field(object, "street_line1", true));
1044   TRY_RESULT(street_line2, get_json_object_string_field(object, "street_line2", true));
1045   TRY_RESULT(postal_code, get_json_object_string_field(object, "post_code", true));
1046 
1047   TRY_STATUS(check_country_code(country_code));
1048   TRY_STATUS(check_state(state));
1049   TRY_STATUS(check_city(city));
1050   TRY_STATUS(check_street_line(street_line1));
1051   TRY_STATUS(check_street_line(street_line2));
1052   TRY_STATUS(check_postal_code(postal_code));
1053 
1054   return Address(std::move(country_code), std::move(state), std::move(city), std::move(street_line1),
1055                  std::move(street_line2), std::move(postal_code));
1056 }
1057 
operator ==(const OrderInfo & lhs,const OrderInfo & rhs)1058 bool operator==(const OrderInfo &lhs, const OrderInfo &rhs) {
1059   return lhs.name == rhs.name && lhs.phone_number == rhs.phone_number && lhs.email_address == rhs.email_address &&
1060          ((lhs.shipping_address == nullptr && rhs.shipping_address == nullptr) ||
1061           (lhs.shipping_address != nullptr && rhs.shipping_address != nullptr &&
1062            *lhs.shipping_address == *rhs.shipping_address));
1063 }
1064 
operator !=(const OrderInfo & lhs,const OrderInfo & rhs)1065 bool operator!=(const OrderInfo &lhs, const OrderInfo &rhs) {
1066   return !(lhs == rhs);
1067 }
1068 
operator <<(StringBuilder & string_builder,const OrderInfo & order_info)1069 StringBuilder &operator<<(StringBuilder &string_builder, const OrderInfo &order_info) {
1070   string_builder << "[OrderInfo " << tag("name", order_info.name) << tag("phone_number", order_info.phone_number)
1071                  << tag("email_address", order_info.email_address);
1072   if (order_info.shipping_address != nullptr) {
1073     string_builder << *order_info.shipping_address;
1074   }
1075   return string_builder << "]";
1076 }
1077 
get_order_info(tl_object_ptr<telegram_api::paymentRequestedInfo> order_info)1078 unique_ptr<OrderInfo> get_order_info(tl_object_ptr<telegram_api::paymentRequestedInfo> order_info) {
1079   if (order_info == nullptr || order_info->flags_ == 0) {
1080     return nullptr;
1081   }
1082   return td::make_unique<OrderInfo>(std::move(order_info->name_), std::move(order_info->phone_),
1083                                     std::move(order_info->email_),
1084                                     get_address(std::move(order_info->shipping_address_)));
1085 }
1086 
get_order_info_object(const unique_ptr<OrderInfo> & order_info)1087 tl_object_ptr<td_api::orderInfo> get_order_info_object(const unique_ptr<OrderInfo> &order_info) {
1088   if (order_info == nullptr) {
1089     return nullptr;
1090   }
1091   return make_tl_object<td_api::orderInfo>(order_info->name, order_info->phone_number, order_info->email_address,
1092                                            get_address_object(order_info->shipping_address));
1093 }
1094 
operator ==(const ShippingOption & lhs,const ShippingOption & rhs)1095 bool operator==(const ShippingOption &lhs, const ShippingOption &rhs) {
1096   return lhs.id == rhs.id && lhs.title == rhs.title && lhs.price_parts == rhs.price_parts;
1097 }
1098 
operator !=(const ShippingOption & lhs,const ShippingOption & rhs)1099 bool operator!=(const ShippingOption &lhs, const ShippingOption &rhs) {
1100   return !(lhs == rhs);
1101 }
1102 
operator <<(StringBuilder & string_builder,const ShippingOption & shipping_option)1103 StringBuilder &operator<<(StringBuilder &string_builder, const ShippingOption &shipping_option) {
1104   return string_builder << "[ShippingOption " << shipping_option.id << " " << shipping_option.title
1105                         << " with price parts " << format::as_array(shipping_option.price_parts) << "]";
1106 }
1107 
answer_shipping_query(Td * td,int64 shipping_query_id,vector<tl_object_ptr<td_api::shippingOption>> && shipping_options,const string & error_message,Promise<Unit> && promise)1108 void answer_shipping_query(Td *td, int64 shipping_query_id,
1109                            vector<tl_object_ptr<td_api::shippingOption>> &&shipping_options,
1110                            const string &error_message, Promise<Unit> &&promise) {
1111   vector<tl_object_ptr<telegram_api::shippingOption>> options;
1112   for (auto &option : shipping_options) {
1113     if (option == nullptr) {
1114       return promise.set_error(Status::Error(400, "Shipping option must be non-empty"));
1115     }
1116     if (!clean_input_string(option->id_)) {
1117       return promise.set_error(Status::Error(400, "Shipping option identifier must be encoded in UTF-8"));
1118     }
1119     if (!clean_input_string(option->title_)) {
1120       return promise.set_error(Status::Error(400, "Shipping option title must be encoded in UTF-8"));
1121     }
1122 
1123     vector<tl_object_ptr<telegram_api::labeledPrice>> prices;
1124     for (auto &price_part : option->price_parts_) {
1125       if (price_part == nullptr) {
1126         return promise.set_error(Status::Error(400, "Shipping option price part must be non-empty"));
1127       }
1128       if (!clean_input_string(price_part->label_)) {
1129         return promise.set_error(Status::Error(400, "Shipping option price part label must be encoded in UTF-8"));
1130       }
1131 
1132       prices.push_back(make_tl_object<telegram_api::labeledPrice>(std::move(price_part->label_), price_part->amount_));
1133     }
1134 
1135     options.push_back(make_tl_object<telegram_api::shippingOption>(std::move(option->id_), std::move(option->title_),
1136                                                                    std::move(prices)));
1137   }
1138 
1139   td->create_handler<SetBotShippingAnswerQuery>(std::move(promise))
1140       ->send(shipping_query_id, error_message, std::move(options));
1141 }
1142 
answer_pre_checkout_query(Td * td,int64 pre_checkout_query_id,const string & error_message,Promise<Unit> && promise)1143 void answer_pre_checkout_query(Td *td, int64 pre_checkout_query_id, const string &error_message,
1144                                Promise<Unit> &&promise) {
1145   td->create_handler<SetBotPreCheckoutAnswerQuery>(std::move(promise))->send(pre_checkout_query_id, error_message);
1146 }
1147 
get_payment_form(Td * td,FullMessageId full_message_id,const td_api::object_ptr<td_api::paymentFormTheme> & theme,Promise<tl_object_ptr<td_api::paymentForm>> && promise)1148 void get_payment_form(Td *td, FullMessageId full_message_id, const td_api::object_ptr<td_api::paymentFormTheme> &theme,
1149                       Promise<tl_object_ptr<td_api::paymentForm>> &&promise) {
1150   TRY_RESULT_PROMISE(promise, server_message_id, td->messages_manager_->get_invoice_message_id(full_message_id));
1151 
1152   tl_object_ptr<telegram_api::dataJSON> theme_parameters;
1153   if (theme != nullptr) {
1154     theme_parameters = make_tl_object<telegram_api::dataJSON>(string());
1155     theme_parameters->data_ = json_encode<string>(json_object([&theme](auto &o) {
1156       auto get_color = [](int32 color) {
1157         return static_cast<int64>(static_cast<uint32>(color) | 0x000000FF);
1158       };
1159       o("bg_color", get_color(theme->background_color_));
1160       o("text_color", get_color(theme->text_color_));
1161       o("hint_color", get_color(theme->hint_color_));
1162       o("link_color", get_color(theme->link_color_));
1163       o("button_color", get_color(theme->button_color_));
1164       o("button_text_color", get_color(theme->button_text_color_));
1165     }));
1166   }
1167   td->create_handler<GetPaymentFormQuery>(std::move(promise))
1168       ->send(full_message_id.get_dialog_id(), server_message_id, std::move(theme_parameters));
1169 }
1170 
validate_order_info(Td * td,FullMessageId full_message_id,tl_object_ptr<td_api::orderInfo> order_info,bool allow_save,Promise<tl_object_ptr<td_api::validatedOrderInfo>> && promise)1171 void validate_order_info(Td *td, FullMessageId full_message_id, tl_object_ptr<td_api::orderInfo> order_info,
1172                          bool allow_save, Promise<tl_object_ptr<td_api::validatedOrderInfo>> &&promise) {
1173   TRY_RESULT_PROMISE(promise, server_message_id, td->messages_manager_->get_invoice_message_id(full_message_id));
1174 
1175   if (order_info != nullptr) {
1176     if (!clean_input_string(order_info->name_)) {
1177       return promise.set_error(Status::Error(400, "Name must be encoded in UTF-8"));
1178     }
1179     if (!clean_input_string(order_info->phone_number_)) {
1180       return promise.set_error(Status::Error(400, "Phone number must be encoded in UTF-8"));
1181     }
1182     if (!clean_input_string(order_info->email_address_)) {
1183       return promise.set_error(Status::Error(400, "Email address must be encoded in UTF-8"));
1184     }
1185     if (order_info->shipping_address_ != nullptr) {
1186       if (!clean_input_string(order_info->shipping_address_->country_code_)) {
1187         return promise.set_error(Status::Error(400, "Country code must be encoded in UTF-8"));
1188       }
1189       if (!clean_input_string(order_info->shipping_address_->state_)) {
1190         return promise.set_error(Status::Error(400, "State must be encoded in UTF-8"));
1191       }
1192       if (!clean_input_string(order_info->shipping_address_->city_)) {
1193         return promise.set_error(Status::Error(400, "City must be encoded in UTF-8"));
1194       }
1195       if (!clean_input_string(order_info->shipping_address_->street_line1_)) {
1196         return promise.set_error(Status::Error(400, "Street address must be encoded in UTF-8"));
1197       }
1198       if (!clean_input_string(order_info->shipping_address_->street_line2_)) {
1199         return promise.set_error(Status::Error(400, "Street address must be encoded in UTF-8"));
1200       }
1201       if (!clean_input_string(order_info->shipping_address_->postal_code_)) {
1202         return promise.set_error(Status::Error(400, "Postal code must be encoded in UTF-8"));
1203       }
1204     }
1205   }
1206 
1207   td->create_handler<ValidateRequestedInfoQuery>(std::move(promise))
1208       ->send(full_message_id.get_dialog_id(), server_message_id, convert_order_info(std::move(order_info)), allow_save);
1209 }
1210 
send_payment_form(Td * td,FullMessageId full_message_id,int64 payment_form_id,const string & order_info_id,const string & shipping_option_id,const tl_object_ptr<td_api::InputCredentials> & credentials,int64 tip_amount,Promise<tl_object_ptr<td_api::paymentResult>> && promise)1211 void send_payment_form(Td *td, FullMessageId full_message_id, int64 payment_form_id, const string &order_info_id,
1212                        const string &shipping_option_id, const tl_object_ptr<td_api::InputCredentials> &credentials,
1213                        int64 tip_amount, Promise<tl_object_ptr<td_api::paymentResult>> &&promise) {
1214   TRY_RESULT_PROMISE(promise, server_message_id, td->messages_manager_->get_invoice_message_id(full_message_id));
1215 
1216   if (credentials == nullptr) {
1217     return promise.set_error(Status::Error(400, "Input payment credentials must be non-empty"));
1218   }
1219 
1220   tl_object_ptr<telegram_api::InputPaymentCredentials> input_credentials;
1221   switch (credentials->get_id()) {
1222     case td_api::inputCredentialsSaved::ID: {
1223       auto credentials_saved = static_cast<const td_api::inputCredentialsSaved *>(credentials.get());
1224       auto credentials_id = credentials_saved->saved_credentials_id_;
1225       if (!clean_input_string(credentials_id)) {
1226         return promise.set_error(Status::Error(400, "Credentials identifier must be encoded in UTF-8"));
1227       }
1228       auto temp_password_state = PasswordManager::get_temp_password_state_sync();
1229       if (!temp_password_state.has_temp_password) {
1230         return promise.set_error(Status::Error(400, "Temporary password required to use saved credentials"));
1231       }
1232 
1233       input_credentials = make_tl_object<telegram_api::inputPaymentCredentialsSaved>(
1234           std::move(credentials_id), BufferSlice(temp_password_state.temp_password));
1235       break;
1236     }
1237     case td_api::inputCredentialsNew::ID: {
1238       auto credentials_new = static_cast<const td_api::inputCredentialsNew *>(credentials.get());
1239       int32 flags = 0;
1240       if (credentials_new->allow_save_) {
1241         flags |= telegram_api::inputPaymentCredentials::SAVE_MASK;
1242       }
1243 
1244       input_credentials = make_tl_object<telegram_api::inputPaymentCredentials>(
1245           flags, false /*ignored*/, make_tl_object<telegram_api::dataJSON>(credentials_new->data_));
1246       break;
1247     }
1248     case td_api::inputCredentialsGooglePay::ID: {
1249       auto credentials_google_pay = static_cast<const td_api::inputCredentialsGooglePay *>(credentials.get());
1250       input_credentials = make_tl_object<telegram_api::inputPaymentCredentialsGooglePay>(
1251           make_tl_object<telegram_api::dataJSON>(credentials_google_pay->data_));
1252       break;
1253     }
1254     case td_api::inputCredentialsApplePay::ID: {
1255       auto credentials_apple_pay = static_cast<const td_api::inputCredentialsApplePay *>(credentials.get());
1256       input_credentials = make_tl_object<telegram_api::inputPaymentCredentialsApplePay>(
1257           make_tl_object<telegram_api::dataJSON>(credentials_apple_pay->data_));
1258       break;
1259     }
1260     default:
1261       UNREACHABLE();
1262   }
1263 
1264   td->create_handler<SendPaymentFormQuery>(std::move(promise))
1265       ->send(full_message_id.get_dialog_id(), server_message_id, payment_form_id, order_info_id, shipping_option_id,
1266              std::move(input_credentials), tip_amount);
1267 }
1268 
get_payment_receipt(Td * td,FullMessageId full_message_id,Promise<tl_object_ptr<td_api::paymentReceipt>> && promise)1269 void get_payment_receipt(Td *td, FullMessageId full_message_id,
1270                          Promise<tl_object_ptr<td_api::paymentReceipt>> &&promise) {
1271   TRY_RESULT_PROMISE(promise, server_message_id,
1272                      td->messages_manager_->get_payment_successful_message_id(full_message_id));
1273   td->create_handler<GetPaymentReceiptQuery>(std::move(promise))
1274       ->send(full_message_id.get_dialog_id(), server_message_id);
1275 }
1276 
get_saved_order_info(Td * td,Promise<tl_object_ptr<td_api::orderInfo>> && promise)1277 void get_saved_order_info(Td *td, Promise<tl_object_ptr<td_api::orderInfo>> &&promise) {
1278   td->create_handler<GetSavedInfoQuery>(std::move(promise))->send();
1279 }
1280 
delete_saved_order_info(Td * td,Promise<Unit> && promise)1281 void delete_saved_order_info(Td *td, Promise<Unit> &&promise) {
1282   td->create_handler<ClearSavedInfoQuery>(std::move(promise))->send(false, true);
1283 }
1284 
delete_saved_credentials(Td * td,Promise<Unit> && promise)1285 void delete_saved_credentials(Td *td, Promise<Unit> &&promise) {
1286   td->create_handler<ClearSavedInfoQuery>(std::move(promise))->send(true, false);
1287 }
1288 
get_bank_card_info(Td * td,const string & bank_card_number,Promise<td_api::object_ptr<td_api::bankCardInfo>> && promise)1289 void get_bank_card_info(Td *td, const string &bank_card_number,
1290                         Promise<td_api::object_ptr<td_api::bankCardInfo>> &&promise) {
1291   td->create_handler<GetBankCardInfoQuery>(std::move(promise))->send(bank_card_number);
1292 }
1293 
1294 }  // namespace td
1295