Strong typing for passport data.

GitOrigin-RevId: 766b671c97d8deb1e32bbfb4972c5a59a67f8435
This commit is contained in:
levlam 2018-04-11 17:21:24 +03:00
parent 7149f65461
commit 0bfe50a7b7
15 changed files with 665 additions and 148 deletions

View File

@ -745,6 +745,10 @@ webPageInstantView page_blocks:vector<PageBlock> is_full:Bool = WebPageInstantVi
webPage url:string display_url:string type:string site_name:string title:string description:string photo:photo embed_url:string embed_type:string embed_width:int32 embed_height:int32 duration:int32 author:string animation:animation audio:audio document:document sticker:sticker video:video video_note:videoNote voice_note:voiceNote has_instant_view:Bool = WebPage;
//@description Describes an address @country_code A two-letter ISO 3166-1 alpha-2 country code @state State, if applicable @city City @street_line1 First line of the address @street_line2 Second line of the address @postal_code Address postal code
address country_code:string state:string city:string street_line1:string street_line2:string postal_code:string = Address;
//@description Portion of the price of a product (e.g., "delivery cost", "tax amount") @label Label for this portion of the product price @amount Currency amount in minimal quantity of the currency
labeledPricePart label:string amount:int53 = LabeledPricePart;
@ -754,11 +758,8 @@ labeledPricePart label:string amount:int53 = LabeledPricePart;
//@send_email_address_to_provider True, if the user's email address will be sent to the provider @is_flexible True, if the total price depends on the shipping method
invoice currency:string price_parts:vector<labeledPricePart> is_test:Bool need_name:Bool need_phone_number:Bool need_email_address:Bool need_shipping_address:Bool send_phone_number_to_provider:Bool send_email_address_to_provider:Bool is_flexible:Bool = Invoice;
//@description Describes a shipping address @country_code Two-letter ISO 3166-1 alpha-2 country code @state State, if applicable @city City @street_line1 First line of the address @street_line2 Second line of the address @postal_code Address postal code
shippingAddress country_code:string state:string city:string street_line1:string street_line2:string postal_code:string = ShippingAddress;
//@description Order information @name Name of the user @phone_number Phone number of the user @email_address Email address of the user @shipping_address Shipping address for this order; may be null
orderInfo name:string phone_number:string email_address:string shipping_address:shippingAddress = OrderInfo;
orderInfo name:string phone_number:string email_address:string shipping_address:address = OrderInfo;
//@description One shipping option @id Shipping option identifier @title Option title @price_parts A list of objects used to calculate the total shipping costs
shippingOption id:string title:string price_parts:vector<labeledPricePart> = ShippingOption;
@ -831,18 +832,92 @@ passportDataTypePhoneNumber = PassportDataType;
passportDataTypeEmailAddress = PassportDataType;
//@description Contains information about a Telegram Passport data @type Telegram Passport data type @data TODO data should be typed @files List of attached files with a document @selfie Selfie with the document
passportData type:PassportDataType data:string files:vector<file> selfie:file = PassportData;
//@description Represents a date according to Gregorian calendar @day A day of a month, 1-31 @month A month, 1-12 @year A year, 1-9999
date day:int32 month:int32 year:int32 = Date;
//@description Contains information about a Telegram Passport data to save @type Telegram Passport data type @data TODO data should be typed @files List of attached files with a document @selfie Selfie with the document
inputPassportData type:PassportDataType data:string files:vector<InputFile> selfie:InputFile = InputPassportData;
//@description Contains user's personal details @first_name First name of the user @last_name Last name of the user @birthdate Birthdate of the user
//@gender Gender of the user, "male" or "female" @country_code A two-letter ISO 3166-1 alpha-2 country code for the user's country
personalDetails first_name:string last_name:string birthdate:date gender:string country_code:string = PersonalDetails;
//@description Contains information about all filled Telegram Passport data @data All filled Telegram Passport data
allPassportData data:vector<passportData> = AllPassportData;
//@description An identity document @number Document's number @expiry_date Document's expiry date @files List of files with the document images @selfie Selfie with the document; may be null
identityDocument number:string expiry_date:date files:vector<file> selfie:file = IdentityDocument;
//@description An identity document to save @number Document's number @expiry_date Document's expiry date @files List of files with the document images @selfie Selfie with the document, if available
inputIdentityDocument number:string expiry_date:date files:vector<InputFile> selfie:InputFile = InputIdentityDocument;
//@class PassportData @description Contains information about a Telegram Passport data
//@description The Telegram Passport data contains a user's personal details @personal_details Personal details of the user
passportDataPersonalDetails personal_details:personalDetails = PassportData;
//@description The Telegram Passport data contains a user's passport @passport The passport
passportDataPassport passport:identityDocument = PassportData;
//@description The Telegram Passport data contains a user's driver license @driver_license The driver license
passportDataDriverLicense driver_license:identityDocument = PassportData;
//@description The Telegram Passport data contains a user's identity card @identity_card The identity card
passportDataIdentityCard identity_card:identityDocument = PassportData;
//@description The Telegram Passport data contains a user's address @address The address
passportDataAddress address:address = PassportData;
//@description The Telegram Passport data contains a user's utility bill @files List of files with the utility bill
passportDataUtilityBill files:vector<file> = PassportData;
//@description The Telegram Passport data contains a user's bank statement @files List of files with the bank statement
passportDataBankStatement files:vector<file> = PassportData;
//@description The Telegram Passport data contains a user's rental agreement @files List of files with the rental agreement
passportDataRentalAgreement files:vector<file> = PassportData;
//@description The Telegram Passport data contains a user's phone number @phone_number The phone number
passportDataPhoneNumber phone_number:string = PassportData;
//@description The Telegram Passport data contains a user's email address @email_address The email address
passportDataEmailAddress email_address:string = PassportData;
//@class InputPassportData @description Contains information about a Telegram Passport data to save
//@description The Telegram Passport data to save contains a user's personal details @personal_details Personal details of the user
inputPassportDataPersonalDetails personal_details:personalDetails = InputPassportData;
//@description The Telegram Passport data to save contains a user's passport @passport The passport to save
inputPassportDataPassport passport:inputIdentityDocument = InputPassportData;
//@description The Telegram Passport data to save contains a user's driver license @driver_license The driver license to save
inputPassportDataDriverLicense driver_license:inputIdentityDocument = InputPassportData;
//@description The Telegram Passport data to save contains a user's identity card @identity_card The identity card to save
inputPassportDataIdentityCard identity_card:inputIdentityDocument = InputPassportData;
//@description The Telegram Passport data to save contains a user's address @address The address
inputPassportDataAddress address:address = InputPassportData;
//@description The Telegram Passport data to save contains a user's utility bill @files List of files with the utility bill
inputPassportDataUtilityBill files:vector<InputFile> = InputPassportData;
//@description The Telegram Passport data to save contains a user's bank statement @files List of files with the bank statement
inputPassportDataBankStatement files:vector<InputFile> = InputPassportData;
//@description The Telegram Passport data to save contains a user's rental agreement @files List of files with the rental agreement
inputPassportDataRentalAgreement files:vector<InputFile> = InputPassportData;
//@description The Telegram Passport data to save contains a user's phone number @phone_number The phone number
inputPassportDataPhoneNumber phone_number:string = InputPassportData;
//@description The Telegram Passport data to save contains a user's email address @email_address The email address
inputPassportDataEmailAddress email_address:string = InputPassportData;
//@description Contains information about all saved Telegram Passport data @data All saved Telegram Passport data
allPassportData data:vector<PassportData> = AllPassportData;
//@description Contains information about requested Telegram Passport authorization form @id Authorization form unique identifier @data Available data @is_selfie_required True, if selfie is required with a document @privacy_policy_url URL with the service privacy policy
passportAuthorizationForm id:int32 data:vector<passportData> is_selfie_required:Bool privacy_policy_url:string = PassportAuthorizationForm;
passportAuthorizationForm id:int32 data:vector<PassportData> is_selfie_required:Bool privacy_policy_url:string = PassportAuthorizationForm;
//@description Contains an encrypted Telegram Passport data credentials @data The encrypted credentials @hash The decrypted data hash @secret Encrypted by service public key secret for data decryption
@ -2011,7 +2086,7 @@ updateNewCallbackQuery id:int64 sender_user_id:int32 chat_id:int53 message_id:in
updateNewInlineCallbackQuery id:int64 sender_user_id:int32 inline_message_id:string chat_instance:int64 payload:CallbackQueryPayload = Update;
//@description A new incoming shipping query; for bots only. Only for invoices with flexible price @id Unique query identifier @sender_user_id Identifier of the user who sent the query @invoice_payload Invoice payload @shipping_address User shipping address
updateNewShippingQuery id:int64 sender_user_id:int32 invoice_payload:string shipping_address:shippingAddress = Update;
updateNewShippingQuery id:int64 sender_user_id:int32 invoice_payload:string shipping_address:address = Update;
//@description A new incoming pre-checkout query; for bots only. Contains full information about a checkout @id Unique query identifier @sender_user_id Identifier of the user who sent the query @currency Currency for the product price @total_amount Total price for the product, in the minimal quantity of the currency
//@invoice_payload Invoice payload @shipping_option_id Identifier of a shipping option chosen by the user; may be empty if not applicable @order_info Information about the order; may be null
@ -2894,7 +2969,7 @@ getPassportData type:PassportDataType password:string = PassportData;
getAllPassportData password:string = AllPassportData;
//@description Sets Telegram Passport data @data Input Telegram Passport data @password Password of the current user
setPassportData data:inputPassportData password:string = PassportData;
setPassportData data:InputPassportData password:string = PassportData;
//@description Deletes Telegram Passport data @type Data type
deletePassportData type:PassportDataType = Ok;

Binary file not shown.

View File

@ -175,7 +175,7 @@ void DeviceTokenManager::register_device(tl_object_ptr<td_api::DeviceToken> devi
token = json_encode<string>(json_object([&device_token](auto &o) {
o("endpoint", device_token->endpoint_);
o("keys", json_object([&device_token](auto &o) {
o("pb256dh", device_token->p256dh_base64url_);
o("p256dh", device_token->p256dh_base64url_);
o("auth", device_token->auth_base64url_);
}));
}));

View File

@ -174,18 +174,16 @@ static tl_object_ptr<td_api::paymentsProviderStripe> convert_payment_provider(
return nullptr;
}
static tl_object_ptr<td_api::shippingAddress> convert_shipping_address(
tl_object_ptr<telegram_api::postAddress> address) {
static tl_object_ptr<td_api::address> convert_address(tl_object_ptr<telegram_api::postAddress> address) {
if (address == nullptr) {
return nullptr;
}
return make_tl_object<td_api::shippingAddress>(std::move(address->country_iso2_), std::move(address->state_),
std::move(address->city_), std::move(address->street_line1_),
std::move(address->street_line2_), std::move(address->post_code_));
return make_tl_object<td_api::address>(std::move(address->country_iso2_), std::move(address->state_),
std::move(address->city_), std::move(address->street_line1_),
std::move(address->street_line2_), std::move(address->post_code_));
}
static tl_object_ptr<telegram_api::postAddress> convert_shipping_address(
tl_object_ptr<td_api::shippingAddress> address) {
static tl_object_ptr<telegram_api::postAddress> convert_address(tl_object_ptr<td_api::address> address) {
if (address == nullptr) {
return nullptr;
}
@ -201,7 +199,7 @@ static tl_object_ptr<td_api::orderInfo> convert_order_info(
}
return make_tl_object<td_api::orderInfo>(std::move(order_info->name_), std::move(order_info->phone_),
std::move(order_info->email_),
convert_shipping_address(std::move(order_info->shipping_address_)));
convert_address(std::move(order_info->shipping_address_)));
}
static tl_object_ptr<td_api::labeledPricePart> convert_labeled_price(
@ -240,7 +238,7 @@ static tl_object_ptr<telegram_api::paymentRequestedInfo> convert_order_info(
}
return make_tl_object<telegram_api::paymentRequestedInfo>(
flags, std::move(order_info->name_), std::move(order_info->phone_number_), std::move(order_info->email_address_),
convert_shipping_address(std::move(order_info->shipping_address_)));
convert_address(std::move(order_info->shipping_address_)));
}
static tl_object_ptr<td_api::savedCredentials> convert_saved_credentials(
@ -525,41 +523,141 @@ StringBuilder &operator<<(StringBuilder &string_builder, const Invoice &invoice)
<< invoice.currency << " with price parts " << format::as_array(invoice.price_parts) << "]";
}
bool operator==(const ShippingAddress &lhs, const ShippingAddress &rhs) {
bool operator==(const Address &lhs, const Address &rhs) {
return lhs.country_code == rhs.country_code && lhs.state == rhs.state && lhs.city == rhs.city &&
lhs.street_line1 == rhs.street_line1 && lhs.street_line2 == rhs.street_line2 &&
lhs.postal_code == rhs.postal_code;
}
bool operator!=(const ShippingAddress &lhs, const ShippingAddress &rhs) {
bool operator!=(const Address &lhs, const Address &rhs) {
return !(lhs == rhs);
}
StringBuilder &operator<<(StringBuilder &string_builder, const ShippingAddress &shipping_address) {
return string_builder << "[Address " << tag("country_code", shipping_address.country_code)
<< tag("state", shipping_address.state) << tag("city", shipping_address.city)
<< tag("street_line1", shipping_address.street_line1)
<< tag("street_line2", shipping_address.street_line2)
<< tag("postal_code", shipping_address.postal_code) << "]";
StringBuilder &operator<<(StringBuilder &string_builder, const Address &address) {
return string_builder << "[Address " << tag("country_code", address.country_code) << tag("state", address.state)
<< tag("city", address.city) << tag("street_line1", address.street_line1)
<< tag("street_line2", address.street_line2) << tag("postal_code", address.postal_code) << "]";
}
unique_ptr<ShippingAddress> get_shipping_address(tl_object_ptr<telegram_api::postAddress> address) {
unique_ptr<Address> get_address(tl_object_ptr<telegram_api::postAddress> &&address) {
if (address == nullptr) {
return nullptr;
}
return make_unique<ShippingAddress>(std::move(address->country_iso2_), std::move(address->state_),
std::move(address->city_), std::move(address->street_line1_),
std::move(address->street_line2_), std::move(address->post_code_));
return make_unique<Address>(std::move(address->country_iso2_), std::move(address->state_), std::move(address->city_),
std::move(address->street_line1_), std::move(address->street_line2_),
std::move(address->post_code_));
}
tl_object_ptr<td_api::shippingAddress> get_shipping_address_object(
const unique_ptr<ShippingAddress> &shipping_address) {
if (shipping_address == nullptr) {
static bool is_capital_alpha(char c) {
return 'A' <= c && c <= 'Z';
}
Status check_country_code(string &country_code) {
if (!clean_input_string(country_code)) {
return Status::Error(400, "Country code must be encoded in UTF-8");
}
if (country_code.size() != 2 || !is_capital_alpha(country_code[0]) || !is_capital_alpha(country_code[1])) {
return Status::Error(400, "Wrong country code specified");
}
return Status::OK();
}
static Status check_state(string &state) {
if (!clean_input_string(state)) {
return Status::Error(400, "State must be encoded in UTF-8");
}
return Status::OK();
}
static Status check_city(string &city) {
if (!clean_input_string(city)) {
return Status::Error(400, "City must be encoded in UTF-8");
}
return Status::OK();
}
static Status check_street_line(string &street_line) {
if (!clean_input_string(street_line)) {
return Status::Error(400, "Street line must be encoded in UTF-8");
}
return Status::OK();
}
static Status check_postal_code(string &postal_code) {
if (!clean_input_string(postal_code)) {
return Status::Error(400, "Postal code must be encoded in UTF-8");
}
return Status::OK();
}
Result<Address> get_address(td_api::object_ptr<td_api::address> &&address) {
if (address == nullptr) {
return Status::Error(400, "Address must not be empty");
}
TRY_STATUS(check_country_code(address->country_code_));
TRY_STATUS(check_state(address->state_));
TRY_STATUS(check_city(address->city_));
TRY_STATUS(check_street_line(address->street_line1_));
TRY_STATUS(check_street_line(address->street_line2_));
TRY_STATUS(check_postal_code(address->postal_code_));
return Address(std::move(address->country_code_), std::move(address->state_), std::move(address->city_),
std::move(address->street_line1_), std::move(address->street_line2_),
std::move(address->postal_code_));
}
tl_object_ptr<td_api::address> get_address_object(const unique_ptr<Address> &address) {
if (address == nullptr) {
return nullptr;
}
return make_tl_object<td_api::shippingAddress>(shipping_address->country_code, shipping_address->state,
shipping_address->city, shipping_address->street_line1,
shipping_address->street_line2, shipping_address->postal_code);
return get_address_object(*address);
}
tl_object_ptr<td_api::address> get_address_object(const Address &address) {
return make_tl_object<td_api::address>(address.country_code, address.state, address.city, address.street_line1,
address.street_line2, address.postal_code);
}
string address_to_json(const Address &address) {
return json_encode<std::string>(json_object([&](auto &o) {
o("country_code", address.country_code);
o("state", address.state);
o("city", address.city);
o("street_line1", address.street_line1);
o("street_line2", address.street_line2);
o("postal_code", address.postal_code);
}));
}
Result<Address> address_from_json(Slice json) {
auto json_copy = json.str();
auto r_value = json_decode(json_copy);
if (r_value.is_error()) {
return Status::Error(400, "Can't parse address JSON object");
}
auto value = r_value.move_as_ok();
if (value.type() != JsonValue::Type::Object) {
return Status::Error(400, "Address should be an Object");
}
auto &object = value.get_object();
TRY_RESULT(country_code, get_json_object_string_field(object, "country_code", true));
TRY_RESULT(state, get_json_object_string_field(object, "state", true));
TRY_RESULT(city, get_json_object_string_field(object, "city", true));
TRY_RESULT(street_line1, get_json_object_string_field(object, "street_line1", true));
TRY_RESULT(street_line2, get_json_object_string_field(object, "street_line2", true));
TRY_RESULT(postal_code, get_json_object_string_field(object, "postal_code", true));
TRY_STATUS(check_country_code(country_code));
TRY_STATUS(check_state(state));
TRY_STATUS(check_city(city));
TRY_STATUS(check_street_line(street_line1));
TRY_STATUS(check_street_line(street_line2));
TRY_STATUS(check_postal_code(postal_code));
return Address(std::move(country_code), std::move(state), std::move(city), std::move(street_line1),
std::move(street_line2), std::move(postal_code));
}
bool operator==(const OrderInfo &lhs, const OrderInfo &rhs) {
@ -587,8 +685,7 @@ unique_ptr<OrderInfo> get_order_info(tl_object_ptr<telegram_api::paymentRequeste
return nullptr;
}
return make_unique<OrderInfo>(std::move(order_info->name_), std::move(order_info->phone_),
std::move(order_info->email_),
get_shipping_address(std::move(order_info->shipping_address_)));
std::move(order_info->email_), get_address(std::move(order_info->shipping_address_)));
}
tl_object_ptr<td_api::orderInfo> get_order_info_object(const unique_ptr<OrderInfo> &order_info) {
@ -596,7 +693,7 @@ tl_object_ptr<td_api::orderInfo> get_order_info_object(const unique_ptr<OrderInf
return nullptr;
}
return make_tl_object<td_api::orderInfo>(order_info->name, order_info->phone_number, order_info->email_address,
get_shipping_address_object(order_info->shipping_address));
get_address_object(order_info->shipping_address));
}
bool operator==(const ShippingOption &lhs, const ShippingOption &rhs) {

View File

@ -12,6 +12,7 @@
#include "td/telegram/Photo.h"
#include "td/utils/common.h"
#include "td/utils/Slice.h"
#include "td/utils/StringBuilder.h"
#include "td/telegram/td_api.h"
@ -46,7 +47,7 @@ struct Invoice {
}
};
struct ShippingAddress {
struct Address {
string country_code;
string state;
string city;
@ -54,9 +55,9 @@ struct ShippingAddress {
string street_line2;
string postal_code;
ShippingAddress() = default;
ShippingAddress(string &&country_code, string &&state, string &&city, string &&street_line1, string &&street_line2,
string &&postal_code)
Address() = default;
Address(string &&country_code, string &&state, string &&city, string &&street_line1, string &&street_line2,
string &&postal_code)
: country_code(std::move(country_code))
, state(std::move(state))
, city(std::move(city))
@ -70,11 +71,10 @@ struct OrderInfo {
string name;
string phone_number;
string email_address;
unique_ptr<ShippingAddress> shipping_address;
unique_ptr<Address> shipping_address;
OrderInfo() = default;
OrderInfo(string &&name, string &&phone_number, string &&email_address,
unique_ptr<ShippingAddress> &&shipping_address)
OrderInfo(string &&name, string &&phone_number, string &&email_address, unique_ptr<Address> &&shipping_address)
: name(std::move(name))
, phone_number(std::move(phone_number))
, email_address(std::move(email_address))
@ -98,14 +98,24 @@ bool operator!=(const Invoice &lhs, const Invoice &rhs);
StringBuilder &operator<<(StringBuilder &string_builder, const Invoice &invoice);
bool operator==(const ShippingAddress &lhs, const ShippingAddress &rhs);
bool operator!=(const ShippingAddress &lhs, const ShippingAddress &rhs);
bool operator==(const Address &lhs, const Address &rhs);
bool operator!=(const Address &lhs, const Address &rhs);
StringBuilder &operator<<(StringBuilder &string_builder, const ShippingAddress &shipping_address);
StringBuilder &operator<<(StringBuilder &string_builder, const Address &address);
unique_ptr<ShippingAddress> get_shipping_address(tl_object_ptr<telegram_api::postAddress> address);
unique_ptr<Address> get_address(tl_object_ptr<telegram_api::postAddress> &&address);
tl_object_ptr<td_api::shippingAddress> get_shipping_address_object(const unique_ptr<ShippingAddress> &shipping_address);
Result<Address> get_address(td_api::object_ptr<td_api::address> &&address);
tl_object_ptr<td_api::address> get_address_object(const unique_ptr<Address> &address);
tl_object_ptr<td_api::address> get_address_object(const Address &address);
string address_to_json(const Address &address);
Result<Address> address_from_json(Slice json);
Status check_country_code(string &country_code);
bool operator==(const OrderInfo &lhs, const OrderInfo &rhs);
bool operator!=(const OrderInfo &lhs, const OrderInfo &rhs);

View File

@ -59,23 +59,23 @@ void parse(Invoice &invoice, ParserT &parser) {
}
template <class StorerT>
void store(const ShippingAddress &shipping_address, StorerT &storer) {
store(shipping_address.country_code, storer);
store(shipping_address.state, storer);
store(shipping_address.city, storer);
store(shipping_address.street_line1, storer);
store(shipping_address.street_line2, storer);
store(shipping_address.postal_code, storer);
void store(const Address &address, StorerT &storer) {
store(address.country_code, storer);
store(address.state, storer);
store(address.city, storer);
store(address.street_line1, storer);
store(address.street_line2, storer);
store(address.postal_code, storer);
}
template <class ParserT>
void parse(ShippingAddress &shipping_address, ParserT &parser) {
parse(shipping_address.country_code, parser);
parse(shipping_address.state, parser);
parse(shipping_address.city, parser);
parse(shipping_address.street_line1, parser);
parse(shipping_address.street_line2, parser);
parse(shipping_address.postal_code, parser);
void parse(Address &address, ParserT &parser) {
parse(address.country_code, parser);
parse(address.state, parser);
parse(address.city, parser);
parse(address.street_line1, parser);
parse(address.street_line2, parser);
parse(address.postal_code, parser);
}
template <class StorerT>
@ -126,7 +126,7 @@ void parse(OrderInfo &order_info, ParserT &parser) {
parse(order_info.email_address, parser);
}
if (has_shipping_address) {
order_info.shipping_address = make_unique<ShippingAddress>();
order_info.shipping_address = make_unique<Address>();
parse(*order_info.shipping_address, parser);
}
}

View File

@ -386,28 +386,28 @@ class GetPassportAuthorizationForm : public NetQueryCallback {
std::vector<TdApiSecureValue> values;
auto types = get_secure_value_types(std::move(authorization_form_->required_types_));
for (auto type : types) {
optional<EncryptedSecureValue> encrypted_secure_value;
for (auto &value : authorization_form_->values_) {
auto value_type = get_secure_value_type(std::move(value->type_));
if (value_type != type) {
continue;
}
encrypted_secure_value = get_encrypted_secure_value(file_manager, std::move(value));
auto r_secure_value = decrypt_encrypted_secure_value(
file_manager, *secret_, get_encrypted_secure_value(file_manager, std::move(value)));
if (r_secure_value.is_error()) {
LOG(ERROR) << "Failed to decrypt secure value: " << r_secure_value.error();
break;
}
auto r_passport_data = get_passport_data_object(file_manager, std::move(r_secure_value.move_as_ok().value));
if (r_passport_data.is_error()) {
LOG(ERROR) << "Failed to get passport data object: " << r_passport_data.error();
break;
}
values.push_back(r_passport_data.move_as_ok());
break;
}
SecureValue secure_value;
secure_value.type = type;
if (encrypted_secure_value) {
auto r_secure_value =
decrypt_encrypted_secure_value(file_manager, *secret_, std::move(*encrypted_secure_value));
if (r_secure_value.is_ok()) {
secure_value = r_secure_value.move_as_ok().value;
} else {
LOG(ERROR) << "Failed to decrypt secure value: " << r_secure_value.error();
}
}
values.push_back(get_passport_data_object(file_manager, std::move(secure_value)));
}
promise_.set_value(make_tl_object<td_api::passportAuthorizationForm>(authorization_form_id_, std::move(values),
authorization_form_->selfie_required_,
@ -426,7 +426,12 @@ void SecureManager::get_secure_value(std::string password, SecureValueType type,
return promise.set_error(r_secure_value.move_as_error());
}
auto *file_manager = G()->td().get_actor_unsafe()->file_manager_.get();
promise.set_value(get_passport_data_object(file_manager, r_secure_value.move_as_ok().value));
auto r_passport_data = get_passport_data_object(file_manager, r_secure_value.move_as_ok().value);
if (r_passport_data.is_error()) {
LOG(ERROR) << "Failed to get passport data object: " << r_passport_data.error();
return promise.set_value(nullptr);
}
promise.set_value(r_passport_data.move_as_ok());
});
do_get_secure_value(std::move(password), type, std::move(new_promise));
}
@ -453,7 +458,12 @@ void SecureManager::set_secure_value(string password, SecureValue secure_value,
return promise.set_error(r_secure_value.move_as_error());
}
auto *file_manager = G()->td().get_actor_unsafe()->file_manager_.get();
promise.set_value(get_passport_data_object(file_manager, r_secure_value.move_as_ok().value));
auto r_passport_data = get_passport_data_object(file_manager, r_secure_value.move_as_ok().value);
if (r_passport_data.is_error()) {
LOG(ERROR) << "Failed to get passport data object: " << r_passport_data.error();
return promise.set_error(Status::Error(500, "Failed to get passport data object"));
}
promise.set_value(r_passport_data.move_as_ok());
});
set_secure_value_queries_[type] = create_actor<SetSecureValue>("SetSecureValue", actor_shared(), std::move(password),
std::move(secure_value), std::move(new_promise));

View File

@ -26,7 +26,7 @@
namespace td {
using TdApiSecureValue = td_api::object_ptr<td_api::passportData>;
using TdApiSecureValue = td_api::object_ptr<td_api::PassportData>;
using TdApiAllSecureValues = td_api::object_ptr<td_api::allPassportData>;
using TdApiAuthorizationForm = td_api::object_ptr<td_api::passportAuthorizationForm>;

View File

@ -8,6 +8,8 @@
#include "td/telegram/DialogId.h"
#include "td/telegram/files/FileManager.h"
#include "td/telegram/misc.h"
#include "td/telegram/Payments.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
@ -392,45 +394,360 @@ td_api::object_ptr<td_api::encryptedCredentials> get_encrypted_credentials_objec
credentials.encrypted_secret);
}
Result<SecureValue> get_secure_value(FileManager *file_manager,
td_api::object_ptr<td_api::inputPassportData> &&input_passport_data) {
if (input_passport_data == nullptr) {
return Status::Error(400, "InputPassportData must not be empty");
static string lpad0(string str, size_t size) {
if (str.size() >= size) {
return str;
}
return string(size - str.size(), '0') + str;
}
// TODO tests
static Status check_date(int32 day, int32 month, int32 year) {
if (day < 1 || day > 31) {
return Status::Error(400, "Wrong day number specified");
}
if (month < 1 || month > 12) {
return Status::Error(400, "Wrong month number specified");
}
if (year < 1 || year > 9999) {
return Status::Error(400, "Wrong year number specified");
}
SecureValue res;
res.type = get_secure_value_type_td_api(std::move(input_passport_data->type_));
res.data = std::move(input_passport_data->data_);
for (auto &file : input_passport_data->files_) {
TRY_RESULT(file_id, file_manager->get_input_file_id(FileType::Secure, std::move(file), DialogId(), false, false,
false, true));
res.files.push_back(file_id);
bool is_leap = month == 2 && (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
const int32 days_in_month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (day > days_in_month[month - 1] + static_cast<int32>(is_leap)) {
return Status::Error(400, "Wrong day in month number specified");
}
if (input_passport_data->selfie_) {
TRY_RESULT(file_id, file_manager->get_input_file_id(FileType::Secure, std::move(input_passport_data->selfie_),
DialogId(), false, false, false, true));
return Status::OK();
}
static Result<string> get_date(td_api::object_ptr<td_api::date> &&date) {
if (date == nullptr) {
return Status::Error(400, "Date must not be empty");
}
TRY_STATUS(check_date(date->day_, date->month_, date->year_));
return PSTRING() << lpad0(to_string(date->day_), 2) << '.' << lpad0(to_string(date->month_), 2) << '.'
<< lpad0(to_string(date->year_), 4);
}
static Result<td_api::object_ptr<td_api::date>> get_date_object(Slice date) {
if (date.size() != 10u) {
return Status::Error(400, "Date has wrong size");
}
auto parts = full_split(date, '.');
if (parts.size() != 3 || parts[0].size() != 2 || parts[1].size() != 2 || parts[2].size() != 4) {
return Status::Error(400, "Date has wrong parts");
}
TRY_RESULT(day, to_integer_safe<int32>(parts[0]));
TRY_RESULT(month, to_integer_safe<int32>(parts[1]));
TRY_RESULT(year, to_integer_safe<int32>(parts[2]));
TRY_STATUS(check_date(day, month, year));
return td_api::make_object<td_api::date>(day, month, year);
}
static Status check_first_name(string &first_name) {
if (!clean_input_string(first_name)) {
return Status::Error(400, "First name must be encoded in UTF-8");
}
return Status::OK();
}
static Status check_last_name(string &last_name) {
if (!clean_input_string(last_name)) {
return Status::Error(400, "Last name must be encoded in UTF-8");
}
return Status::OK();
}
static Status check_gender(string &gender) {
if (gender != "male" && gender != "female") {
return Status::Error(400, "Unsupported gender specified");
}
return Status::OK();
}
static Result<string> get_personal_details(td_api::object_ptr<td_api::personalDetails> &&personal_details) {
if (personal_details == nullptr) {
return Status::Error(400, "Personal details must not be empty");
}
TRY_STATUS(check_first_name(personal_details->first_name_));
TRY_STATUS(check_last_name(personal_details->last_name_));
TRY_RESULT(birthdate, get_date(std::move(personal_details->birthdate_)));
TRY_STATUS(check_gender(personal_details->gender_));
TRY_STATUS(check_country_code(personal_details->country_code_));
return json_encode<std::string>(json_object([&](auto &o) {
o("first_name", personal_details->first_name_);
o("last_name", personal_details->last_name_);
o("birth_date", birthdate);
o("gender", personal_details->gender_);
o("country_code", personal_details->country_code_);
}));
}
static Result<td_api::object_ptr<td_api::personalDetails>> get_personal_details_object(Slice personal_details) {
auto personal_details_copy = personal_details.str();
auto r_value = json_decode(personal_details_copy);
if (r_value.is_error()) {
return Status::Error(400, "Can't parse personal details JSON object");
}
auto value = r_value.move_as_ok();
if (value.type() != JsonValue::Type::Object) {
return Status::Error(400, "Personal details should be an Object");
}
auto &object = value.get_object();
TRY_RESULT(first_name, get_json_object_string_field(object, "first_name", true));
TRY_RESULT(last_name, get_json_object_string_field(object, "last_name", true));
TRY_RESULT(birthdate, get_json_object_string_field(object, "birth_date", true));
TRY_RESULT(gender, get_json_object_string_field(object, "gender", true));
TRY_RESULT(country_code, get_json_object_string_field(object, "country_code", true));
TRY_STATUS(check_first_name(first_name));
TRY_STATUS(check_last_name(last_name));
TRY_RESULT(date, get_date_object(birthdate));
TRY_STATUS(check_gender(gender));
TRY_STATUS(check_country_code(country_code));
return td_api::make_object<td_api::personalDetails>(std::move(first_name), std::move(last_name), std::move(date),
std::move(gender), std::move(country_code));
}
static Status check_document_number(string &number) {
if (!clean_input_string(number)) {
return Status::Error(400, "Document number must be encoded in UTF-8");
}
return Status::OK();
}
static Result<FileId> get_secure_file(FileManager *file_manager, td_api::object_ptr<td_api::InputFile> &&file) {
return file_manager->get_input_file_id(FileType::Secure, std::move(file), DialogId(), false, false, false, true);
}
static Result<vector<FileId>> get_secure_files(FileManager *file_manager,
vector<td_api::object_ptr<td_api::InputFile>> &&files) {
vector<FileId> result;
for (auto &file : files) {
TRY_RESULT(file_id, get_secure_file(file_manager, std::move(file)));
result.push_back(file_id);
}
return result;
}
static Result<SecureValue> get_identity_document(
SecureValueType type, FileManager *file_manager,
td_api::object_ptr<td_api::inputIdentityDocument> &&identity_document) {
if (identity_document == nullptr) {
return Status::Error(400, "Identity document must not be empty");
}
TRY_STATUS(check_document_number(identity_document->number_));
TRY_RESULT(date, get_date(std::move(identity_document->expiry_date_)));
TRY_RESULT(files, get_secure_files(file_manager, std::move(identity_document->files_)));
SecureValue res;
res.type = type;
res.data = json_encode<std::string>(json_object([&](auto &o) {
o("document_no", identity_document->number_);
o("expiry_date", date);
}));
res.files = std::move(files);
if (identity_document->selfie_ != nullptr) {
TRY_RESULT(file_id, get_secure_file(file_manager, std::move(identity_document->selfie_)));
res.selfie = file_id;
}
return res;
}
td_api::object_ptr<td_api::passportData> get_passport_data_object(FileManager *file_manager, const SecureValue &value) {
std::vector<td_api::object_ptr<td_api::file>> files;
files = transform(value.files, [&](FileId id) { return file_manager->get_file_object(id, true); });
static Result<td_api::object_ptr<td_api::identityDocument>> get_identity_document_object(FileManager *file_manager,
const SecureValue &value) {
auto files = transform(value.files, [file_manager](FileId id) { return file_manager->get_file_object(id); });
td_api::object_ptr<td_api::file> selfie;
if (value.selfie.is_valid()) {
selfie = file_manager->get_file_object(value.selfie, true);
selfie = file_manager->get_file_object(value.selfie);
}
return td_api::make_object<td_api::passportData>(get_passport_data_type_object(value.type), value.data,
std::move(files), std::move(selfie));
auto data_copy = value.data;
auto r_value = json_decode(data_copy);
if (r_value.is_error()) {
return Status::Error(400, "Can't parse identity document JSON object");
}
auto json_value = r_value.move_as_ok();
if (json_value.type() != JsonValue::Type::Object) {
return Status::Error(400, "Identity document should be an Object");
}
auto &object = json_value.get_object();
TRY_RESULT(number, get_json_object_string_field(object, "document_no", true));
TRY_RESULT(expiry_date, get_json_object_string_field(object, "expiry_date", true));
TRY_STATUS(check_document_number(number));
TRY_RESULT(date, get_date_object(expiry_date));
return td_api::make_object<td_api::identityDocument>(std::move(number), std::move(date), std::move(files),
std::move(selfie));
}
static Status check_phone_number(string &phone_number) {
if (!clean_input_string(phone_number)) {
return Status::Error(400, "Phone number must be encoded in UTF-8");
}
return Status::OK();
}
static Status check_email_address(string &email_address) {
if (!clean_input_string(email_address)) {
return Status::Error(400, "Email address must be encoded in UTF-8");
}
return Status::OK();
}
Result<SecureValue> get_secure_value(FileManager *file_manager,
td_api::object_ptr<td_api::InputPassportData> &&input_passport_data) {
if (input_passport_data == nullptr) {
return Status::Error(400, "InputPassportData must not be empty");
}
SecureValue res;
switch (input_passport_data->get_id()) {
case td_api::inputPassportDataPersonalDetails::ID: {
auto input = td_api::move_object_as<td_api::inputPassportDataPersonalDetails>(input_passport_data);
res.type = SecureValueType::PersonalDetails;
TRY_RESULT(personal_details, get_personal_details(std::move(input->personal_details_)));
res.data = std::move(personal_details);
break;
}
case td_api::inputPassportDataPassport::ID: {
auto input = td_api::move_object_as<td_api::inputPassportDataPassport>(input_passport_data);
return get_identity_document(SecureValueType::Passport, file_manager, std::move(input->passport_));
}
case td_api::inputPassportDataDriverLicense::ID: {
auto input = td_api::move_object_as<td_api::inputPassportDataDriverLicense>(input_passport_data);
return get_identity_document(SecureValueType::DriverLicense, file_manager, std::move(input->driver_license_));
}
case td_api::inputPassportDataIdentityCard::ID: {
auto input = td_api::move_object_as<td_api::inputPassportDataIdentityCard>(input_passport_data);
return get_identity_document(SecureValueType::IdentityCard, file_manager, std::move(input->identity_card_));
}
case td_api::inputPassportDataAddress::ID: {
auto input = td_api::move_object_as<td_api::inputPassportDataAddress>(input_passport_data);
res.type = SecureValueType::Address;
TRY_RESULT(address, get_address(std::move(input->address_)));
res.data = address_to_json(address);
break;
}
case td_api::inputPassportDataUtilityBill::ID: {
auto input = td_api::move_object_as<td_api::inputPassportDataUtilityBill>(input_passport_data);
res.type = SecureValueType::UtilityBill;
TRY_RESULT(files, get_secure_files(file_manager, std::move(input->files_)));
res.files = std::move(files);
break;
}
case td_api::inputPassportDataBankStatement::ID: {
auto input = td_api::move_object_as<td_api::inputPassportDataBankStatement>(input_passport_data);
res.type = SecureValueType::BankStatement;
TRY_RESULT(files, get_secure_files(file_manager, std::move(input->files_)));
res.files = std::move(files);
break;
}
case td_api::inputPassportDataRentalAgreement::ID: {
auto input = td_api::move_object_as<td_api::inputPassportDataRentalAgreement>(input_passport_data);
res.type = SecureValueType::RentalAgreement;
TRY_RESULT(files, get_secure_files(file_manager, std::move(input->files_)));
res.files = std::move(files);
break;
}
case td_api::inputPassportDataPhoneNumber::ID: {
auto input = td_api::move_object_as<td_api::inputPassportDataPhoneNumber>(input_passport_data);
res.type = SecureValueType::PhoneNumber;
TRY_STATUS(check_phone_number(input->phone_number_));
res.data = std::move(input->phone_number_);
break;
}
case td_api::inputPassportDataEmailAddress::ID: {
auto input = td_api::move_object_as<td_api::inputPassportDataEmailAddress>(input_passport_data);
res.type = SecureValueType::EmailAddress;
TRY_STATUS(check_email_address(input->email_address_));
res.data = std::move(input->email_address_);
break;
}
default:
UNREACHABLE();
}
return res;
}
Result<td_api::object_ptr<td_api::PassportData>> get_passport_data_object(FileManager *file_manager,
const SecureValue &value) {
switch (value.type) {
case SecureValueType::PersonalDetails: {
TRY_RESULT(personal_details, get_personal_details_object(value.data));
return td_api::make_object<td_api::passportDataPersonalDetails>(std::move(personal_details));
}
case SecureValueType::Passport: {
TRY_RESULT(passport, get_identity_document_object(file_manager, value));
return td_api::make_object<td_api::passportDataPassport>(std::move(passport));
}
case SecureValueType::DriverLicense: {
TRY_RESULT(driver_license, get_identity_document_object(file_manager, value));
return td_api::make_object<td_api::passportDataDriverLicense>(std::move(driver_license));
}
case SecureValueType::IdentityCard: {
TRY_RESULT(identity_card, get_identity_document_object(file_manager, value));
return td_api::make_object<td_api::passportDataIdentityCard>(std::move(identity_card));
}
case SecureValueType::Address: {
TRY_RESULT(address, address_from_json(value.data));
return td_api::make_object<td_api::passportDataAddress>(get_address_object(address));
}
case SecureValueType::UtilityBill:
case SecureValueType::BankStatement:
case SecureValueType::RentalAgreement: {
auto files = transform(value.files, [file_manager](FileId id) { return file_manager->get_file_object(id); });
if (value.type == SecureValueType::UtilityBill) {
return td_api::make_object<td_api::passportDataUtilityBill>(std::move(files));
}
if (value.type == SecureValueType::BankStatement) {
return td_api::make_object<td_api::passportDataBankStatement>(std::move(files));
}
if (value.type == SecureValueType::RentalAgreement) {
return td_api::make_object<td_api::passportDataRentalAgreement>(std::move(files));
}
UNREACHABLE();
break;
}
case SecureValueType::PhoneNumber:
return td_api::make_object<td_api::passportDataPhoneNumber>(value.data);
case SecureValueType::EmailAddress:
return td_api::make_object<td_api::passportDataEmailAddress>(value.data);
case SecureValueType::None:
default:
UNREACHABLE();
return Status::Error(400, "Wrong value type");
}
}
td_api::object_ptr<td_api::allPassportData> get_all_passport_data_object(FileManager *file_manager,
const vector<SecureValue> &value) {
return td_api::make_object<td_api::allPassportData>(transform(
value, [file_manager](const SecureValue &value) { return get_passport_data_object(file_manager, value); }));
const vector<SecureValue> &values) {
vector<td_api::object_ptr<td_api::PassportData>> result;
result.reserve(values.size());
for (auto &value : values) {
auto r_obj = get_passport_data_object(file_manager, value);
if (r_obj.is_error()) {
LOG(ERROR) << "Can't get passport data object: " << r_obj.error();
continue;
}
result.push_back(r_obj.move_as_ok());
}
return td_api::make_object<td_api::allPassportData>(std::move(result));
}
Result<std::pair<FileId, SecureFileCredentials>> decrypt_secure_file(FileManager *file_manager,
@ -588,21 +905,21 @@ EncryptedSecureValue encrypt_secure_value(FileManager *file_manager, const secur
return res;
}
auto as_jsonable(const SecureDataCredentials &credentials) {
static auto as_jsonable(const SecureDataCredentials &credentials) {
return json_object([&credentials](auto &o) {
o("data_hash", base64_encode(credentials.hash));
o("secret", base64_encode(credentials.secret));
});
}
auto as_jsonable(const SecureFileCredentials &credentials) {
static auto as_jsonable(const SecureFileCredentials &credentials) {
return json_object([&credentials](auto &o) {
o("file_hash", base64_encode(credentials.hash));
o("secret", base64_encode(credentials.secret));
});
}
auto as_jsonable(const vector<SecureFileCredentials> &files) {
static auto as_jsonable(const vector<SecureFileCredentials> &files) {
return json_array([&files](auto &arr) {
for (auto &file : files) {
arr(as_jsonable(file));
@ -610,7 +927,7 @@ auto as_jsonable(const vector<SecureFileCredentials> &files) {
});
}
Slice secure_value_type_as_slice(SecureValueType type) {
static Slice secure_value_type_as_slice(SecureValueType type) {
switch (type) {
case SecureValueType::PersonalDetails:
return Slice("personal_details");
@ -629,7 +946,7 @@ Slice secure_value_type_as_slice(SecureValueType type) {
case SecureValueType::RentalAgreement:
return Slice("rental_agreement");
case SecureValueType::PhoneNumber:
return Slice("phone");
return Slice("phone_number");
case SecureValueType::EmailAddress:
return Slice("email");
default:
@ -639,10 +956,14 @@ Slice secure_value_type_as_slice(SecureValueType type) {
}
}
auto credentials_as_jsonable(std::vector<SecureValueCredentials> &credentials, Slice payload) {
static auto credentials_as_jsonable(std::vector<SecureValueCredentials> &credentials, Slice payload) {
return json_object([&credentials, &payload](auto &o) {
o("secure_data", json_object([&credentials](auto &o) {
for (auto &c : credentials) {
if (c.type == SecureValueType::PhoneNumber || c.type == SecureValueType::EmailAddress) {
continue;
}
o(secure_value_type_as_slice(c.type), json_object([&credentials = c](auto &o) {
if (credentials.data) {
o("data", as_jsonable(credentials.data.value()));
@ -673,4 +994,5 @@ Result<EncryptedSecureCredentials> encrypted_credentials(std::vector<SecureValue
res.encrypted_secret = encrypted_secret.as_slice().str();
return res;
}
} // namespace td

View File

@ -172,12 +172,13 @@ struct SecureValueWithCredentials {
};
Result<SecureValue> get_secure_value(FileManager *file_manager,
td_api::object_ptr<td_api::inputPassportData> &&input_passport_data);
td_api::object_ptr<td_api::InputPassportData> &&input_passport_data);
td_api::object_ptr<td_api::passportData> get_passport_data_object(FileManager *file_manager, const SecureValue &value);
Result<td_api::object_ptr<td_api::PassportData>> get_passport_data_object(FileManager *file_manager,
const SecureValue &value);
td_api::object_ptr<td_api::allPassportData> get_all_passport_data_object(FileManager *file_manager,
const vector<SecureValue> &value);
const vector<SecureValue> &values);
Result<std::pair<FileId, SecureFileCredentials>> decrypt_secure_file(FileManager *file_manager,
const secure_storage::Secret &secret,

View File

@ -1777,8 +1777,7 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateBotShippingQuer
make_tl_object<td_api::updateNewShippingQuery>(
update->query_id_, td_->contacts_manager_->get_user_id_object(user_id, "updateNewShippingQuery"),
update->payload_.as_slice().str(),
get_shipping_address_object(get_shipping_address(
std::move(update->shipping_address_))))); // TODO use convert_shipping_address
get_address_object(get_address(std::move(update->shipping_address_))))); // TODO use convert_address
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateBotPrecheckoutQuery> update, bool /*force_apply*/) {

View File

@ -952,28 +952,30 @@ class CliClient final : public Actor {
return transform(full_split(types, delimiter), [](Slice str) { return as_passport_data_type(str); });
}
static tl_object_ptr<td_api::inputPassportData> as_input_passport_data(string passport_data_type, string file) {
static tl_object_ptr<td_api::InputPassportData> as_input_passport_data(string passport_data_type, string arg) {
vector<td_api::object_ptr<td_api::InputFile>> files;
LOG(ERROR) << "FILE " << file;
if (!file.empty()) {
files.push_back(make_tl_object<td_api::inputFileLocal>(file));
if (!arg.empty()) {
files.push_back(make_tl_object<td_api::inputFileLocal>(arg));
}
auto data_type = as_passport_data_type(passport_data_type);
string data;
if (passport_data_type == "address" || passport_data_type == "a") {
data = "cucumber lives here";
return make_tl_object<td_api::inputPassportDataAddress>(
make_tl_object<td_api::address>("US", "CA", "Los Angeles", "Washington", "", "90001"));
} else if (passport_data_type == "email" || passport_data_type == "e") {
data = file;
files.clear();
return make_tl_object<td_api::inputPassportDataEmailAddress>(arg);
} else if (passport_data_type == "phone" || passport_data_type == "p") {
data = file;
files.clear();
return make_tl_object<td_api::inputPassportDataPhoneNumber>(arg);
} else if (passport_data_type == "pd") {
data = "{todo}";
} else {
data = "I am cucumber";
return make_tl_object<td_api::inputPassportDataPersonalDetails>(make_tl_object<td_api::personalDetails>(
"Mike", "Towers", make_tl_object<td_api::date>(29, 2, 1999), "male", "US"));
} else if (passport_data_type == "driver_license" || passport_data_type == "dl") {
return make_tl_object<td_api::inputPassportDataDriverLicense>(make_tl_object<td_api::inputIdentityDocument>(
"1234567890", make_tl_object<td_api::date>(1, 3, 2029), std::move(files), nullptr));
} else if (passport_data_type == "rental_aggrement" || passport_data_type == "ra") {
return make_tl_object<td_api::inputPassportDataRentalAgreement>(std::move(files));
}
return make_tl_object<td_api::inputPassportData>(std::move(data_type), std::move(data), std::move(files), nullptr);
LOG(ERROR) << "Unsupported passport data type " << passport_data_type;
return nullptr;
}
static td_api::object_ptr<td_api::Object> execute(tl_object_ptr<td_api::Function> f) {
@ -1143,10 +1145,10 @@ class CliClient final : public Actor {
} else if (op == "spd") {
string password;
string passport_data_type;
string file;
string arg;
std::tie(password, args) = split(args);
std::tie(passport_data_type, file) = split(args);
send_request(make_tl_object<td_api::setPassportData>(as_input_passport_data(passport_data_type, file), password));
std::tie(passport_data_type, arg) = split(args);
send_request(make_tl_object<td_api::setPassportData>(as_input_passport_data(passport_data_type, arg), password));
} else if (op == "pdu" || op == "processDcUpdate") {
string dc_id;
string ip_port;

View File

@ -371,8 +371,7 @@ struct PhotoRemoteFileLocation {
inline StringBuilder &operator<<(StringBuilder &string_builder, const PhotoRemoteFileLocation &location) {
return string_builder << "[id = " << location.id_ << ", access_hash = " << location.access_hash_
<< ", volume_id = " << location.volume_id_ << ", secret = " << location.secret_
<< ", local_id = " << location.local_id_ << "]";
<< ", volume_id = " << location.volume_id_ << ", local_id = " << location.local_id_ << "]";
}
struct WebRemoteFileLocation {

View File

@ -1976,9 +1976,6 @@ Result<FileId> FileManager::get_input_thumbnail_file_id(const tl_object_ptr<td_a
Result<FileId> FileManager::get_input_file_id(FileType type, const tl_object_ptr<td_api::InputFile> &file,
DialogId owner_dialog_id, bool allow_zero, bool is_encrypted,
bool get_by_hash, bool is_secure) {
if (is_encrypted) {
get_by_hash = false;
}
if (!file) {
if (allow_zero) {
return FileId();
@ -1986,6 +1983,10 @@ Result<FileId> FileManager::get_input_file_id(FileType type, const tl_object_ptr
return Status::Error(6, "InputFile not specified");
}
if (is_encrypted || is_secure) {
get_by_hash = false;
}
auto new_type = is_encrypted ? FileType::Encrypted : (is_secure ? FileType::Secure : type);
auto r_file_id = [&]() -> Result<FileId> {

View File

@ -774,7 +774,7 @@ void to_json(JsonValueScope &jv, const T &value) {
template <class F>
class JsonObjectImpl : Jsonable {
public:
JsonObjectImpl(F &&f) : f_(std::forward<F>(f)) {
explicit JsonObjectImpl(F &&f) : f_(std::forward<F>(f)) {
}
void store(JsonValueScope *scope) const {
auto object = scope->enter_object();
@ -792,7 +792,7 @@ auto json_object(F &&f) {
template <class F>
class JsonArrayImpl : Jsonable {
public:
JsonArrayImpl(F &&f) : f_(std::forward<F>(f)) {
explicit JsonArrayImpl(F &&f) : f_(std::forward<F>(f)) {
}
void store(JsonValueScope *scope) const {
auto array = scope->enter_array();
@ -802,6 +802,7 @@ class JsonArrayImpl : Jsonable {
private:
F f_;
};
template <class F>
auto json_array(F &&f) {
return JsonArrayImpl<F>(std::forward<F>(f));