diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index e766445b..00dd9a47 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -817,6 +817,9 @@ passportDataTypeDriverLicense = PassportDataType; //@description The Telegram Passport data contains a user's identity card passportDataTypeIdentityCard = PassportDataType; +//@description The Telegram Passport data contains a user's internal passport +passportDataTypeInternalPassport = PassportDataType; + //@description The Telegram Passport data contains a user's address passportDataTypeAddress = PassportDataType; @@ -829,6 +832,12 @@ passportDataTypeBankStatement = PassportDataType; //@description The Telegram Passport data contains a user's rental agreement passportDataTypeRentalAgreement = PassportDataType; +//@description The Telegram Passport data contains a user's passport registration +passportDataTypePassportRegistration = PassportDataType; + +//@description The Telegram Passport data contains a user's temporary registration +passportDataTypeTemporaryRegistration = PassportDataType; + //@description The Telegram Passport data contains a user's phone number passportDataTypePhoneNumber = PassportDataType; @@ -840,14 +849,16 @@ passportDataTypeEmailAddress = PassportDataType; date day:int32 month:int32 year:int32 = Date; //@description Contains user's personal details @first_name First name of the user; 1-255 characters @last_name Last name of the user; 1-255 characters @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; +//@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 @residence_country_code A two-letter ISO 3166-1 alpha-2 country code for the user's residence country +personalDetails first_name:string last_name:string birthdate:date gender:string country_code:string residence_country_code:string = PersonalDetails; -//@description An identity document @number Document's number; 1-24 characters @expiry_date Document's expiry date; may be null @files List of files with the document images @selfie Selfie with the document; may be null -identityDocument number:string expiry_date:date files:vector selfie:datedFile = IdentityDocument; +//@description An identity document @number Document's number; 1-24 characters @expiry_date Document's expiry date; may be null @front_side Document's front side +//@reverse_side Document's reverse side, only for driver license and identity card @selfie Selfie with the document; may be null +identityDocument number:string expiry_date:date front_side:datedFile reverse_side:datedFile selfie:datedFile = IdentityDocument; -//@description An identity document to save @number Document's number @expiry_date Document's expiry date, if available @files List of files with the document images; must be non-empty @selfie Selfie with the document, if available -inputIdentityDocument number:string expiry_date:date files:vector selfie:InputFile = InputIdentityDocument; +//@description An identity document to save @number Document's number @expiry_date Document's expiry date, if available @front_side Document's front side +//@reverse_side Document's reverse side, only for driver license and identity card @selfie Selfie with the document, if available +inputIdentityDocument number:string expiry_date:date front_side:InputFile reverse_side:InputFile selfie:InputFile = InputIdentityDocument; //@class PassportData @description Contains information about a Telegram Passport data @@ -864,6 +875,9 @@ 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 internal passport @internal_passport The internal passport +passportDataInternalPassport internal_passport:identityDocument = PassportData; + //@description The Telegram Passport data contains a user's address @address The address passportDataAddress address:address = PassportData; @@ -876,6 +890,12 @@ passportDataBankStatement files:vector = PassportData; //@description The Telegram Passport data contains a user's rental agreement @files List of files with the rental agreement passportDataRentalAgreement files:vector = PassportData; +//@description The Telegram Passport data contains a user's passport registration @files List of files with the passport registration +passportDataPassportRegistration files:vector = PassportData; + +//@description The Telegram Passport data contains a user's temporary registration @files List of files with the temporary registration +passportDataTemporaryRegistration files:vector = PassportData; + //@description The Telegram Passport data contains a user's phone number @phone_number The phone number passportDataPhoneNumber phone_number:string = PassportData; @@ -897,6 +917,9 @@ inputPassportDataDriverLicense driver_license:inputIdentityDocument = InputPassp //@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 internal passport @internal_passport The internal passport to save +inputPassportDataInternalPassport internal_passport:inputIdentityDocument = InputPassportData; + //@description The Telegram Passport data to save contains a user's address @address The address inputPassportDataAddress address:address = InputPassportData; @@ -909,6 +932,12 @@ inputPassportDataBankStatement files:vector = 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 = InputPassportData; +//@description The Telegram Passport data to save contains a user's passport registration @files List of files with the passport registration +inputPassportDataPassportRegistration files:vector = InputPassportData; + +//@description The Telegram Passport data to save contains a user's temporary registration @files List of files with the temporary registration +inputPassportDataTemporaryRegistration files:vector = InputPassportData; + //@description The Telegram Passport data to save contains a user's phone number @phone_number The phone number inputPassportDataPhoneNumber phone_number:string = InputPassportData; @@ -925,15 +954,21 @@ allPassportData data:vector = AllPassportData; //@description A field of data contains an error. The error is considered resolved when the field's value changes @field_name Field name passportDataErrorSourceDataField field_name:string = PassportDataErrorSource; +//@description A document front side contains an error. The error is considered resolved when the file with the front side changes +passportDataErrorSourceFrontSide = PassportDataErrorSource; + +//@description A document reverse side contains an error. The error is considered resolved when the file with the reverse side changes +passportDataErrorSourceReverseSide = PassportDataErrorSource; + +//@description A selfie contains an error. The error is considered resolved when the file with the selfie changes +passportDataErrorSourceSelfie = PassportDataErrorSource; + //@description A file contains an error. The error is considered resolved when the file changes passportDataErrorSourceFile = PassportDataErrorSource; //@description A list of attached files contains an error. The error is considered resolved when the file list changes passportDataErrorSourceFiles = PassportDataErrorSource; -//@description A selfie contains an error. The error is considered resolved when the file with the selfie changes -passportDataErrorSourceSelfie = PassportDataErrorSource; - //@description Contains description of an error in a Telegram Passport data @type Telegram Passport data type with the error @message Error message @source Error source passportDataError type:PassportDataType message:string source:PassportDataErrorSource = PassportDataError; @@ -949,8 +984,8 @@ passportAuthorizationForm id:int32 required_types:vector data: encryptedCredentials data:bytes hash:bytes secret:bytes = EncryptedCredentials; -//@description Contains information about an encrypted Telegram Passport data @type Telegram Passport data type @data Encrypted JSON-encoded data about the user @files List of attached files @value Unencrypted data, phone number or email address @selfie Selfie with the document -encryptedPassportData type:PassportDataType data:bytes files:vector value:string selfie:datedFile = EncryptedPassportData; +//@description Contains information about an encrypted Telegram Passport data @type Telegram Passport data type @data Encrypted JSON-encoded data about the user @front_side Identity document's front side @reverse_side Identity document's reverse side; may be null @selfie Selfie with the document; may be null @files List of attached files @value Unencrypted data, phone number or email address +encryptedPassportData type:PassportDataType data:bytes front_side:datedFile reverse_side:datedFile selfie:datedFile files:vector value:string = EncryptedPassportData; //@class InputPassportDataErrorSource @description Contains description of an error in a Telegram Passport data; for bots only @@ -958,15 +993,21 @@ encryptedPassportData type:PassportDataType data:bytes files:vector v //@description A field of data contains an error. The error is considered resolved when the field's value changes @field_name Field name @data_hash Current data hash inputPassportDataErrorSourceDataField field_name:string data_hash:bytes = InputPassportDataErrorSource; +//@description A document front side contains an error. The error is considered resolved when the file with the document front side changes @file_hash Current hash of a file with the front side +inputPassportDataErrorSourceFrontSide file_hash:bytes = InputPassportDataErrorSource; + +//@description A document reverse side contains an error. The error is considered resolved when the file with the document reverse side changes @file_hash Current hash of a file with the reverse side +inputPassportDataErrorSourceReverseSide file_hash:bytes = InputPassportDataErrorSource; + +//@description A selfie contains an error. The error is considered resolved when the file with the selfie changes @file_hash Current hash of a file with the selfie +inputPassportDataErrorSourceSelfie file_hash:bytes = InputPassportDataErrorSource; + //@description A file contains an error. The error is considered resolved when the file changes @file_hash Hash of the file with an error inputPassportDataErrorSourceFile file_hash:bytes = InputPassportDataErrorSource; //@description A list of attached files contains an error. The error is considered resolved when the file list changes @file_hashes Hashes of all files inputPassportDataErrorSourceFiles file_hashes:vector = InputPassportDataErrorSource; -//@description A selfie contains an error. The error is considered resolved when the file with the selfie changes @file_hash Current file with the selfie hash -inputPassportDataErrorSourceSelfie file_hash:bytes = InputPassportDataErrorSource; - //@description Contains description of an error in a Telegram Passport data; for bots only @type Telegram Passport data type with the error @message Error message @source Error source inputPassportDataError type:PassportDataType message:string source:InputPassportDataErrorSource = InputPassportDataError; diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index 8dbadbcb..5af2693e 100644 Binary files a/td/generate/scheme/td_api.tlo and b/td/generate/scheme/td_api.tlo differ diff --git a/td/generate/scheme/telegram_api.tl b/td/generate/scheme/telegram_api.tl index b53623eb..681325eb 100644 --- a/td/generate/scheme/telegram_api.tl +++ b/td/generate/scheme/telegram_api.tl @@ -848,23 +848,28 @@ secureValueTypePersonalDetails#9d2a81e3 = SecureValueType; secureValueTypePassport#3dac6a00 = SecureValueType; secureValueTypeDriverLicense#6e425c4 = SecureValueType; secureValueTypeIdentityCard#a0d0744b = SecureValueType; +secureValueTypeInternalPassport#99a48f23 = SecureValueType; secureValueTypeAddress#cbe31e26 = SecureValueType; secureValueTypeUtilityBill#fc36954e = SecureValueType; secureValueTypeBankStatement#89137c0d = SecureValueType; secureValueTypeRentalAgreement#8b883488 = SecureValueType; +secureValueTypePassportRegistration#99e3806a = SecureValueType; +secureValueTypeTemporaryRegistration#ea02ec33 = SecureValueType; secureValueTypePhone#b320aadb = SecureValueType; secureValueTypeEmail#8e3ca7ee = SecureValueType; -secureValue#ec4134c8 flags:# type:SecureValueType data:flags.0?SecureData files:flags.1?Vector plain_data:flags.2?SecurePlainData selfie:flags.3?SecureFile hash:bytes = SecureValue; +secureValue#b4b4b699 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile files:flags.4?Vector plain_data:flags.5?SecurePlainData hash:bytes = SecureValue; -inputSecureValue#c0da30f0 flags:# type:SecureValueType data:flags.0?SecureData files:flags.1?Vector plain_data:flags.2?SecurePlainData selfie:flags.3?InputSecureFile = InputSecureValue; +inputSecureValue#67872e8 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile files:flags.4?Vector plain_data:flags.5?SecurePlainData = InputSecureValue; secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash; secureValueErrorData#e8a40bd9 type:SecureValueType data_hash:bytes field:string text:string = SecureValueError; +secureValueErrorFrontSide#be3dfa type:SecureValueType file_hash:bytes text:string = SecureValueError; +secureValueErrorReverseSide#868a2aa5 type:SecureValueType file_hash:bytes text:string = SecureValueError; +secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorFile#7a700873 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureValueErrorFiles#666220e9 type:SecureValueType file_hash:Vector text:string = SecureValueError; -secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError; secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted; diff --git a/td/generate/scheme/telegram_api.tlo b/td/generate/scheme/telegram_api.tlo index e9a4a167..ea62d1c7 100644 Binary files a/td/generate/scheme/telegram_api.tlo and b/td/generate/scheme/telegram_api.tlo differ diff --git a/td/telegram/SecureManager.cpp b/td/telegram/SecureManager.cpp index 6cf500f4..0fe63224 100644 --- a/td/telegram/SecureManager.cpp +++ b/td/telegram/SecureManager.cpp @@ -77,6 +77,8 @@ class SetSecureValue : public NetQueryCallback { size_t files_left_to_upload_ = 0; vector to_upload_; + optional front_side_; + optional reverse_side_; optional selfie_; class UploadCallback; @@ -214,6 +216,9 @@ void GetSecureValue::on_result(NetQueryPtr query) { } encrypted_secure_value_ = get_encrypted_secure_value(G()->td().get_actor_unsafe()->file_manager_.get(), std::move(result[0])); + if (encrypted_secure_value_.value().type == SecureValueType::None) { + return on_error(Status::Error(404, "Not Found")); + } loop(); } @@ -309,11 +314,16 @@ void SetSecureValue::UploadCallback::on_upload_error(FileId file_id, Status erro void SetSecureValue::on_upload_ok(FileId file_id, tl_object_ptr input_file) { SecureInputFile *info_ptr = nullptr; for (auto &info : to_upload_) { - if (info.file_id != file_id) { - continue; + if (info.file_id == file_id) { + info_ptr = &info; + break; } - info_ptr = &info; - break; + } + if (front_side_ && front_side_.value().file_id == file_id) { + info_ptr = &front_side_.value(); + } + if (reverse_side_ && reverse_side_.value().file_id == file_id) { + info_ptr = &reverse_side_.value(); } if (selfie_ && selfie_.value().file_id == file_id) { info_ptr = &selfie_.value(); @@ -359,30 +369,49 @@ void SetSecureValue::start_up() { auto *file_manager = G()->td().get_actor_unsafe()->file_manager_.get(); // Remove duplicate files + FileId front_side_file_id; + if (secure_value_.front_side.file_id.is_valid()) { + front_side_file_id = file_manager->get_file_view(secure_value_.front_side.file_id).file_id(); + front_side_ = SecureInputFile(); + } + FileId reverse_side_file_id; + if (secure_value_.reverse_side.file_id.is_valid()) { + reverse_side_file_id = file_manager->get_file_view(secure_value_.reverse_side.file_id).file_id(); + reverse_side_ = SecureInputFile(); + if (front_side_file_id == reverse_side_file_id) { + return on_error(Status::Error(400, "Front side and reverse side must be different")); + } + } FileId selfie_file_id; if (secure_value_.selfie.file_id.is_valid()) { selfie_file_id = file_manager->get_file_view(secure_value_.selfie.file_id).file_id(); selfie_ = SecureInputFile(); + if (front_side_file_id == selfie_file_id) { + return on_error(Status::Error(400, "Front side and selfie must be different")); + } + if (reverse_side_file_id == selfie_file_id) { + return on_error(Status::Error(400, "Reverse side and selfie must be different")); + } } - for (auto it = secure_value_.files.begin(); it != secure_value_.files.end();) { - auto file_id = file_manager->get_file_view(it->file_id).file_id(); - bool is_duplicate = file_id == selfie_file_id; - for (auto pit = secure_value_.files.begin(); pit != it; pit++) { - if (file_id == file_manager->get_file_view(pit->file_id).file_id()) { - is_duplicate = true; - break; + if (!secure_value_.files.empty()) { + CHECK(!front_side_file_id.is_valid()); + CHECK(!reverse_side_file_id.is_valid()); + CHECK(!selfie_file_id.is_valid()); + for (auto it = secure_value_.files.begin(); it != secure_value_.files.end();) { + auto file_id = file_manager->get_file_view(it->file_id).file_id(); + bool is_duplicate = false; + for (auto pit = secure_value_.files.begin(); pit != it; pit++) { + if (file_id == file_manager->get_file_view(pit->file_id).file_id()) { + is_duplicate = true; + break; + } + } + if (is_duplicate) { + it = secure_value_.files.erase(it); + } else { + ++it; } } - if (is_duplicate) { - it = secure_value_.files.erase(it); - } else { - ++it; - } - } - if (selfie_ && secure_value_.files.empty()) { - secure_value_.files.push_back(std::move(secure_value_.selfie)); - selfie_ = optional(); - secure_value_.selfie = DatedFile(); } to_upload_.resize(secure_value_.files.size()); @@ -390,6 +419,12 @@ void SetSecureValue::start_up() { for (size_t i = 0; i < to_upload_.size(); i++) { start_upload(file_manager, secure_value_.files[i].file_id, to_upload_[i]); } + if (front_side_) { + start_upload(file_manager, secure_value_.front_side.file_id, front_side_.value()); + } + if (reverse_side_) { + start_upload(file_manager, secure_value_.reverse_side.file_id, reverse_side_.value()); + } if (selfie_) { start_upload(file_manager, secure_value_.selfie.file_id, selfie_.value()); } @@ -419,8 +454,9 @@ void SetSecureValue::loop() { return; } auto *file_manager = G()->td().get_actor_unsafe()->file_manager_.get(); - auto input_secure_value = get_input_secure_value_object( - file_manager, encrypt_secure_value(file_manager, *secret_, secure_value_), to_upload_, selfie_); + auto input_secure_value = + get_input_secure_value_object(file_manager, encrypt_secure_value(file_manager, *secret_, secure_value_), + to_upload_, front_side_, reverse_side_, selfie_); auto save_secure_value = telegram_api::account_saveSecureValue(std::move(input_secure_value), secret_.value().get_hash()); auto query = G()->net_query_creator().create(create_storer(save_secure_value)); @@ -436,9 +472,18 @@ void SetSecureValue::hangup() { void SetSecureValue::tear_down() { auto *file_manager = G()->td().get_actor_unsafe()->file_manager_.get(); + if (file_manager == nullptr) { + return; + } for (auto &file_info : to_upload_) { file_manager->upload(file_info.file_id, nullptr, 0, 0); } + if (front_side_) { + file_manager->upload(front_side_.value().file_id, nullptr, 0, 0); + } + if (reverse_side_) { + file_manager->upload(reverse_side_.value().file_id, nullptr, 0, 0); + } if (selfie_) { file_manager->upload(selfie_.value().file_id, nullptr, 0, 0); } @@ -452,12 +497,21 @@ void SetSecureValue::on_result(NetQueryPtr query) { auto result = r_result.move_as_ok(); auto *file_manager = G()->td().get_actor_unsafe()->file_manager_.get(); auto encrypted_secure_value = get_encrypted_secure_value(file_manager, std::move(result)); + if (encrypted_secure_value.type == SecureValueType::None) { + return on_error(Status::Error(500, "Receive invalid Telegram Passport data")); + } if (secure_value_.files.size() != encrypted_secure_value.files.size()) { return on_error(Status::Error(500, "Different file count")); } for (size_t i = 0; i < secure_value_.files.size(); i++) { merge(file_manager, secure_value_.files[i].file_id, encrypted_secure_value.files[i]); } + if (secure_value_.front_side.file_id.is_valid() && encrypted_secure_value.front_side.file.file_id.is_valid()) { + merge(file_manager, secure_value_.front_side.file_id, encrypted_secure_value.front_side); + } + if (secure_value_.reverse_side.file_id.is_valid() && encrypted_secure_value.reverse_side.file.file_id.is_valid()) { + merge(file_manager, secure_value_.reverse_side.file_id, encrypted_secure_value.reverse_side); + } if (secure_value_.selfie.file_id.is_valid() && encrypted_secure_value.selfie.file.file_id.is_valid()) { merge(file_manager, secure_value_.selfie.file_id, encrypted_secure_value.selfie); } @@ -649,6 +703,20 @@ class GetPassportAuthorizationForm : public NetQueryCallback { source = td_api::make_object(); break; } + case telegram_api::secureValueErrorFrontSide::ID: { + auto error = move_tl_object_as(error_ptr); + type = get_secure_value_type(error->type_); + message = std::move(error->text_); + source = td_api::make_object(); + break; + } + case telegram_api::secureValueErrorReverseSide::ID: { + auto error = move_tl_object_as(error_ptr); + type = get_secure_value_type(error->type_); + message = std::move(error->text_); + source = td_api::make_object(); + break; + } case telegram_api::secureValueErrorSelfie::ID: { auto error = move_tl_object_as(error_ptr); type = get_secure_value_type(error->type_); @@ -776,6 +844,24 @@ void SecureManager::set_secure_value_errors(Td *td, tl_object_ptrdata_hash_), source->field_name_, error->message_)); break; } + case td_api::inputPassportDataErrorSourceFrontSide::ID: { + auto source = td_api::move_object_as(error->source_); + input_errors.push_back(make_tl_object( + std::move(type), BufferSlice(source->file_hash_), error->message_)); + break; + } + case td_api::inputPassportDataErrorSourceReverseSide::ID: { + auto source = td_api::move_object_as(error->source_); + input_errors.push_back(make_tl_object( + std::move(type), BufferSlice(source->file_hash_), error->message_)); + break; + } + case td_api::inputPassportDataErrorSourceSelfie::ID: { + auto source = td_api::move_object_as(error->source_); + input_errors.push_back(make_tl_object( + std::move(type), BufferSlice(source->file_hash_), error->message_)); + break; + } case td_api::inputPassportDataErrorSourceFile::ID: { auto source = td_api::move_object_as(error->source_); input_errors.push_back(make_tl_object( @@ -792,12 +878,6 @@ void SecureManager::set_secure_value_errors(Td *td, tl_object_ptrmessage_)); break; } - case td_api::inputPassportDataErrorSourceSelfie::ID: { - auto source = td_api::move_object_as(error->source_); - input_errors.push_back(make_tl_object( - std::move(type), BufferSlice(source->file_hash_), error->message_)); - break; - } default: UNREACHABLE(); } diff --git a/td/telegram/SecureValue.cpp b/td/telegram/SecureValue.cpp index 86cbfa46..04b7b517 100644 --- a/td/telegram/SecureValue.cpp +++ b/td/telegram/SecureValue.cpp @@ -38,6 +38,8 @@ StringBuilder &operator<<(StringBuilder &string_builder, const SecureValueType & return string_builder << "DriverLicense"; case SecureValueType::IdentityCard: return string_builder << "IdentityCard"; + case SecureValueType::InternalPassport: + return string_builder << "InternalPassport"; case SecureValueType::Address: return string_builder << "Address"; case SecureValueType::UtilityBill: @@ -46,6 +48,10 @@ StringBuilder &operator<<(StringBuilder &string_builder, const SecureValueType & return string_builder << "BankStatement"; case SecureValueType::RentalAgreement: return string_builder << "RentalAgreement"; + case SecureValueType::PassportRegistration: + return string_builder << "PassportRegistration"; + case SecureValueType::TemporaryRegistration: + return string_builder << "TemporaryRegistration"; case SecureValueType::PhoneNumber: return string_builder << "PhoneNumber"; case SecureValueType::EmailAddress: @@ -69,6 +75,8 @@ SecureValueType get_secure_value_type(const tl_object_ptr get_passport_data_type_object(Secur return td_api::make_object(); case SecureValueType::IdentityCard: return td_api::make_object(); + case SecureValueType::InternalPassport: + return td_api::make_object(); case SecureValueType::Address: return td_api::make_object(); case SecureValueType::UtilityBill: @@ -159,6 +179,10 @@ td_api::object_ptr get_passport_data_type_object(Secur return td_api::make_object(); case SecureValueType::RentalAgreement: return td_api::make_object(); + case SecureValueType::PassportRegistration: + return td_api::make_object(); + case SecureValueType::TemporaryRegistration: + return td_api::make_object(); case SecureValueType::PhoneNumber: return td_api::make_object(); case SecureValueType::EmailAddress: @@ -180,6 +204,8 @@ td_api::object_ptr get_input_secure_value_type(Se return telegram_api::make_object(); case SecureValueType::IdentityCard: return telegram_api::make_object(); + case SecureValueType::InternalPassport: + return telegram_api::make_object(); case SecureValueType::Address: return telegram_api::make_object(); case SecureValueType::UtilityBill: @@ -188,6 +214,10 @@ td_api::object_ptr get_input_secure_value_type(Se return telegram_api::make_object(); case SecureValueType::RentalAgreement: return telegram_api::make_object(); + case SecureValueType::PassportRegistration: + return telegram_api::make_object(); + case SecureValueType::TemporaryRegistration: + return telegram_api::make_object(); case SecureValueType::PhoneNumber: return telegram_api::make_object(); case SecureValueType::EmailAddress: @@ -208,7 +238,7 @@ string get_secure_value_data_field_name(SecureValueType type, string field_name) switch (type) { case SecureValueType::PersonalDetails: if (field_name == "first_name" || field_name == "last_name" || field_name == "gender" || - field_name == "country_code") { + field_name == "country_code" || field_name == "residence_country_code") { return field_name; } if (field_name == "birth_date") { @@ -218,6 +248,7 @@ string get_secure_value_data_field_name(SecureValueType type, string field_name) case SecureValueType::Passport: case SecureValueType::DriverLicense: case SecureValueType::IdentityCard: + case SecureValueType::InternalPassport: if (field_name == "expiry_date") { return field_name; } @@ -237,6 +268,8 @@ string get_secure_value_data_field_name(SecureValueType type, string field_name) case SecureValueType::UtilityBill: case SecureValueType::BankStatement: case SecureValueType::RentalAgreement: + case SecureValueType::PassportRegistration: + case SecureValueType::TemporaryRegistration: case SecureValueType::PhoneNumber: case SecureValueType::EmailAddress: break; @@ -392,13 +425,49 @@ telegram_api::object_ptr get_secure_data_object(const } bool operator==(const EncryptedSecureValue &lhs, const EncryptedSecureValue &rhs) { - return lhs.type == rhs.type && lhs.data == rhs.data && lhs.files == rhs.files && lhs.selfie == rhs.selfie; + return lhs.type == rhs.type && lhs.data == rhs.data && lhs.files == rhs.files && lhs.front_side == rhs.front_side && + lhs.reverse_side == rhs.reverse_side && lhs.selfie == rhs.selfie; } bool operator!=(const EncryptedSecureValue &lhs, const EncryptedSecureValue &rhs) { return !(lhs == rhs); } +static bool check_encrypted_secure_value(const EncryptedSecureValue &value) { + bool has_encrypted_data = !value.data.hash.empty(); + bool has_plain_data = !has_encrypted_data && !value.data.data.empty(); + bool has_files = !value.files.empty(); + bool has_front_side = value.front_side.file.file_id.is_valid(); + bool has_reverse_side = value.reverse_side.file.file_id.is_valid(); + bool has_selfie = value.selfie.file.file_id.is_valid(); + switch (value.type) { + case SecureValueType::PersonalDetails: + case SecureValueType::Address: + return has_encrypted_data && !has_files && !has_front_side && !has_reverse_side && !has_selfie; + case SecureValueType::Passport: + case SecureValueType::InternalPassport: + return has_encrypted_data && !has_files && has_front_side && !has_reverse_side; + case SecureValueType::DriverLicense: + case SecureValueType::IdentityCard: + return has_encrypted_data && !has_files && has_front_side && has_reverse_side; + case SecureValueType::UtilityBill: + case SecureValueType::BankStatement: + case SecureValueType::RentalAgreement: + case SecureValueType::PassportRegistration: + case SecureValueType::TemporaryRegistration: + return !has_encrypted_data && !has_plain_data && has_files && !has_front_side && !has_reverse_side && !has_selfie; + case SecureValueType::PhoneNumber: + return has_plain_data && !has_files && !has_front_side && !has_reverse_side && !has_selfie; + case SecureValueType::EmailAddress: + return has_plain_data && !has_files && !has_front_side && !has_reverse_side && !has_selfie; + case SecureValueType::None: + return false; + default: + UNREACHABLE(); + return false; + } +} + EncryptedSecureValue get_encrypted_secure_value(FileManager *file_manager, tl_object_ptr &&secure_value) { EncryptedSecureValue result; @@ -422,18 +491,34 @@ EncryptedSecureValue get_encrypted_secure_value(FileManager *file_manager, result.data = get_encrypted_secure_data(std::move(secure_value->data_)); } result.files = get_encrypted_secure_files(file_manager, std::move(secure_value->files_)); + if (secure_value->front_side_ != nullptr) { + result.front_side = get_encrypted_secure_file(file_manager, std::move(secure_value->front_side_)); + } + if (secure_value->reverse_side_ != nullptr) { + result.reverse_side = get_encrypted_secure_file(file_manager, std::move(secure_value->reverse_side_)); + } if (secure_value->selfie_ != nullptr) { result.selfie = get_encrypted_secure_file(file_manager, std::move(secure_value->selfie_)); } result.hash = secure_value->hash_.as_slice().str(); + if (!check_encrypted_secure_value(result)) { + LOG(ERROR) << "Receive invalid encrypted secure value of type " << result.type; + return EncryptedSecureValue(); + } return result; } vector get_encrypted_secure_values( FileManager *file_manager, vector> &&secure_values) { - return transform(std::move(secure_values), [file_manager](tl_object_ptr &&secure_value) { - return get_encrypted_secure_value(file_manager, std::move(secure_value)); - }); + vector results; + results.reserve(secure_values.size()); + for (auto &secure_value : secure_values) { + auto result = get_encrypted_secure_value(file_manager, std::move(secure_value)); + if (result.type != SecureValueType::None) { + results.push_back(std::move(result)); + } + } + return results; } td_api::object_ptr get_encrypted_passport_data_object( @@ -441,14 +526,18 @@ td_api::object_ptr get_encrypted_passport_data_ob bool is_plain = value.data.hash.empty(); return td_api::make_object( get_passport_data_type_object(value.type), is_plain ? string() : value.data.data, - get_dated_files_object(file_manager, value.files), is_plain ? value.data.data : string(), - value.selfie.file.file_id.is_valid() ? get_dated_file_object(file_manager, value.selfie) : nullptr); + value.front_side.file.file_id.is_valid() ? get_dated_file_object(file_manager, value.front_side) : nullptr, + value.reverse_side.file.file_id.is_valid() ? get_dated_file_object(file_manager, value.reverse_side) : nullptr, + value.selfie.file.file_id.is_valid() ? get_dated_file_object(file_manager, value.selfie) : nullptr, + get_dated_files_object(file_manager, value.files), is_plain ? value.data.data : string()); } telegram_api::object_ptr get_input_secure_value_object( FileManager *file_manager, const EncryptedSecureValue &value, std::vector &input_files, - optional &selfie) { + optional &front_side, optional &reverse_side, optional &selfie) { bool is_plain = value.type == SecureValueType::PhoneNumber || value.type == SecureValueType::EmailAddress; + bool has_front_side = value.front_side.file.file_id.is_valid(); + bool has_reverse_side = value.reverse_side.file.file_id.is_valid(); bool has_selfie = value.selfie.file.file_id.is_valid(); int32 flags = 0; tl_object_ptr plain_data; @@ -465,14 +554,24 @@ telegram_api::object_ptr get_input_secure_value_ if (!value.files.empty()) { flags |= telegram_api::inputSecureValue::FILES_MASK; } + if (has_front_side) { + flags |= telegram_api::inputSecureValue::FRONT_SIDE_MASK; + CHECK(front_side); + } + if (has_reverse_side) { + flags |= telegram_api::inputSecureValue::REVERSE_SIDE_MASK; + CHECK(reverse_side); + } if (has_selfie) { flags |= telegram_api::inputSecureValue::SELFIE_MASK; CHECK(selfie); } return telegram_api::make_object( flags, get_input_secure_value_type(value.type), is_plain ? nullptr : get_secure_data_object(value.data), - get_input_secure_files_object(file_manager, value.files, input_files), std::move(plain_data), - has_selfie ? get_input_secure_file_object(file_manager, value.selfie, *selfie) : nullptr); + has_front_side ? get_input_secure_file_object(file_manager, value.front_side, *front_side) : nullptr, + has_reverse_side ? get_input_secure_file_object(file_manager, value.reverse_side, *reverse_side) : nullptr, + has_selfie ? get_input_secure_file_object(file_manager, value.selfie, *selfie) : nullptr, + get_input_secure_files_object(file_manager, value.files, input_files), std::move(plain_data)); } vector> get_encrypted_passport_data_object( @@ -626,6 +725,7 @@ static Result get_personal_details(td_api::object_ptrgender_)); TRY_STATUS(check_country_code(personal_details->country_code_)); + TRY_STATUS(check_country_code(personal_details->residence_country_code_)); return json_encode(json_object([&](auto &o) { o("first_name", personal_details->first_name_); @@ -633,6 +733,7 @@ static Result get_personal_details(td_api::object_ptrgender_); o("country_code", personal_details->country_code_); + o("residence_country_code", personal_details->residence_country_code_); })); } @@ -657,15 +758,18 @@ static Result> get_personal_details_ } 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_RESULT(residence_country_code, get_json_object_string_field(object, "residence_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)); + TRY_STATUS(check_country_code(residence_country_code)); return td_api::make_object(std::move(first_name), std::move(last_name), std::move(date), - std::move(gender), std::move(country_code)); + std::move(gender), std::move(country_code), + std::move(residence_country_code)); } static Status check_document_number(string &number) { @@ -700,15 +804,14 @@ static Result> get_secure_files(FileManager *file_manager, return result; } -static Result get_identity_document( - SecureValueType type, FileManager *file_manager, - td_api::object_ptr &&identity_document) { +static Result get_identity_document(SecureValueType type, FileManager *file_manager, + td_api::object_ptr &&identity_document, + bool need_reverse_side) { 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; @@ -717,21 +820,45 @@ static Result get_identity_document( o("expiry_date", date); })); - res.files = std::move(files); + if (identity_document->front_side_ == nullptr) { + return Status::Error(400, "Document's front side is required"); + } + if (identity_document->reverse_side_ == nullptr) { + if (need_reverse_side) { + return Status::Error(400, "Document's reverse side is required"); + } + } else { + if (!need_reverse_side) { + return Status::Error(400, "Document shouldn't have a reverse side"); + } + } + + TRY_RESULT(front_side, get_secure_file(file_manager, std::move(identity_document->front_side_))); + res.front_side = front_side; + if (identity_document->reverse_side_ != nullptr) { + TRY_RESULT(reverse_side, get_secure_file(file_manager, std::move(identity_document->reverse_side_))); + res.reverse_side = reverse_side; + } if (identity_document->selfie_ != nullptr) { - TRY_RESULT(file, get_secure_file(file_manager, std::move(identity_document->selfie_))); - res.selfie = file; + TRY_RESULT(selfie, get_secure_file(file_manager, std::move(identity_document->selfie_))); + res.selfie = selfie; } return res; } static Result> get_identity_document_object(FileManager *file_manager, const SecureValue &value) { - auto files = transform(value.files, [file_manager](const DatedFile &dated_file) { - return get_dated_file_object(file_manager, dated_file); - }); + CHECK(value.files.empty()); + td_api::object_ptr front_side; + td_api::object_ptr reverse_side; td_api::object_ptr selfie; + if (value.front_side.file_id.is_valid()) { + front_side = get_dated_file_object(file_manager, value.front_side); + } + if (value.reverse_side.file_id.is_valid()) { + reverse_side = get_dated_file_object(file_manager, value.reverse_side); + } if (value.selfie.file_id.is_valid()) { selfie = get_dated_file_object(file_manager, value.selfie); } @@ -754,8 +881,8 @@ static Result> get_identity_documen TRY_STATUS(check_document_number(number)); TRY_RESULT(date, get_date_object(expiry_date)); - return td_api::make_object(std::move(number), std::move(date), std::move(files), - std::move(selfie)); + return td_api::make_object(std::move(number), std::move(date), std::move(front_side), + std::move(reverse_side), std::move(selfie)); } static Status check_phone_number(string &phone_number) { @@ -789,15 +916,21 @@ Result get_secure_value(FileManager *file_manager, } case td_api::inputPassportDataPassport::ID: { auto input = td_api::move_object_as(input_passport_data); - return get_identity_document(SecureValueType::Passport, file_manager, std::move(input->passport_)); + return get_identity_document(SecureValueType::Passport, file_manager, std::move(input->passport_), false); } case td_api::inputPassportDataDriverLicense::ID: { auto input = td_api::move_object_as(input_passport_data); - return get_identity_document(SecureValueType::DriverLicense, file_manager, std::move(input->driver_license_)); + return get_identity_document(SecureValueType::DriverLicense, file_manager, std::move(input->driver_license_), + true); } case td_api::inputPassportDataIdentityCard::ID: { auto input = td_api::move_object_as(input_passport_data); - return get_identity_document(SecureValueType::IdentityCard, file_manager, std::move(input->identity_card_)); + return get_identity_document(SecureValueType::IdentityCard, file_manager, std::move(input->identity_card_), true); + } + case td_api::inputPassportDataInternalPassport::ID: { + auto input = td_api::move_object_as(input_passport_data); + return get_identity_document(SecureValueType::InternalPassport, file_manager, + std::move(input->internal_passport_), false); } case td_api::inputPassportDataAddress::ID: { auto input = td_api::move_object_as(input_passport_data); @@ -827,6 +960,20 @@ Result get_secure_value(FileManager *file_manager, res.files = std::move(files); break; } + case td_api::inputPassportDataPassportRegistration::ID: { + auto input = td_api::move_object_as(input_passport_data); + res.type = SecureValueType::PassportRegistration; + TRY_RESULT(files, get_secure_files(file_manager, std::move(input->files_))); + res.files = std::move(files); + break; + } + case td_api::inputPassportDataTemporaryRegistration::ID: { + auto input = td_api::move_object_as(input_passport_data); + res.type = SecureValueType::TemporaryRegistration; + 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(input_passport_data); res.type = SecureValueType::PhoneNumber; @@ -866,13 +1013,19 @@ Result> get_passport_data_object(FileMa TRY_RESULT(identity_card, get_identity_document_object(file_manager, value)); return td_api::make_object(std::move(identity_card)); } + case SecureValueType::InternalPassport: { + TRY_RESULT(internal_passport, get_identity_document_object(file_manager, value)); + return td_api::make_object(std::move(internal_passport)); + } case SecureValueType::Address: { TRY_RESULT(address, address_from_json(value.data)); return td_api::make_object(get_address_object(address)); } case SecureValueType::UtilityBill: case SecureValueType::BankStatement: - case SecureValueType::RentalAgreement: { + case SecureValueType::RentalAgreement: + case SecureValueType::PassportRegistration: + case SecureValueType::TemporaryRegistration: { auto files = transform( value.files, [file_manager](const DatedFile &file) { return get_dated_file_object(file_manager, file); }); if (value.type == SecureValueType::UtilityBill) { @@ -884,6 +1037,12 @@ Result> get_passport_data_object(FileMa if (value.type == SecureValueType::RentalAgreement) { return td_api::make_object(std::move(files)); } + if (value.type == SecureValueType::PassportRegistration) { + return td_api::make_object(std::move(files)); + } + if (value.type == SecureValueType::TemporaryRegistration) { + return td_api::make_object(std::move(files)); + } UNREACHABLE(); break; } @@ -961,13 +1120,17 @@ Result decrypt_secure_value(FileManager *file_manage res_credentials.type = res.type; res_credentials.hash = encrypted_secure_value.hash; switch (encrypted_secure_value.type) { + case SecureValueType::None: + return Status::Error("Receive invalid Telegram Passport data"); case SecureValueType::EmailAddress: case SecureValueType::PhoneNumber: res.data = encrypted_secure_value.data.data; break; case SecureValueType::UtilityBill: case SecureValueType::BankStatement: - case SecureValueType::RentalAgreement: { + case SecureValueType::RentalAgreement: + case SecureValueType::PassportRegistration: + case SecureValueType::TemporaryRegistration: { TRY_RESULT(files, decrypt_secure_files(file_manager, secret, encrypted_secure_value.files)); res.files = std::move(files.first); res_credentials.files = std::move(files.second); @@ -979,9 +1142,17 @@ Result decrypt_secure_value(FileManager *file_manage if (!res.data.empty()) { res_credentials.data = std::move(data.second); } - TRY_RESULT(files, decrypt_secure_files(file_manager, secret, encrypted_secure_value.files)); - res.files = std::move(files.first); - res_credentials.files = std::move(files.second); + CHECK(encrypted_secure_value.files.empty()); + TRY_RESULT(front_side, decrypt_secure_file(file_manager, secret, encrypted_secure_value.front_side)); + res.front_side = std::move(front_side.first); + if (res.front_side.file_id.is_valid()) { + res_credentials.front_side = std::move(front_side.second); + } + TRY_RESULT(reverse_side, decrypt_secure_file(file_manager, secret, encrypted_secure_value.reverse_side)); + res.reverse_side = std::move(reverse_side.first); + if (res.reverse_side.file_id.is_valid()) { + res_credentials.reverse_side = std::move(reverse_side.second); + } TRY_RESULT(selfie, decrypt_secure_file(file_manager, secret, encrypted_secure_value.selfie)); res.selfie = std::move(selfie.first); if (res.selfie.file_id.is_valid()) { @@ -1079,7 +1250,9 @@ EncryptedSecureValue encrypt_secure_value(FileManager *file_manager, const secur break; case SecureValueType::UtilityBill: case SecureValueType::BankStatement: - case SecureValueType::RentalAgreement: { + case SecureValueType::RentalAgreement: + case SecureValueType::PassportRegistration: + case SecureValueType::TemporaryRegistration: { string to_hash; res.files = encrypt_secure_files(file_manager, master_secret, secure_value.files, to_hash); res.hash = secure_storage::calc_value_hash(to_hash).as_slice().str(); @@ -1088,7 +1261,9 @@ EncryptedSecureValue encrypt_secure_value(FileManager *file_manager, const secur default: { string to_hash; res.data = encrypt_secure_data(master_secret, secure_value.data, to_hash); - res.files = encrypt_secure_files(file_manager, master_secret, secure_value.files, to_hash); + CHECK(secure_value.files.empty()); + res.front_side = encrypt_secure_file(file_manager, master_secret, secure_value.front_side, to_hash); + res.reverse_side = encrypt_secure_file(file_manager, master_secret, secure_value.reverse_side, to_hash); res.selfie = encrypt_secure_file(file_manager, master_secret, secure_value.selfie, to_hash); res.hash = secure_storage::calc_value_hash(to_hash).as_slice().str(); break; @@ -1129,6 +1304,8 @@ static Slice secure_value_type_as_slice(SecureValueType type) { return Slice("driver_license"); case SecureValueType::IdentityCard: return Slice("identity_card"); + case SecureValueType::InternalPassport: + return Slice("internal_passport"); case SecureValueType::Address: return Slice("address"); case SecureValueType::UtilityBill: @@ -1137,6 +1314,10 @@ static Slice secure_value_type_as_slice(SecureValueType type) { return Slice("bank_statement"); case SecureValueType::RentalAgreement: return Slice("rental_agreement"); + case SecureValueType::PassportRegistration: + return Slice("passport_registration"); + case SecureValueType::TemporaryRegistration: + return Slice("temporary_registration"); case SecureValueType::PhoneNumber: return Slice("phone_number"); case SecureValueType::EmailAddress: @@ -1163,6 +1344,12 @@ static auto credentials_as_jsonable(std::vector &credent if (!credentials.files.empty()) { o("files", as_jsonable(credentials.files)); } + if (credentials.front_side) { + o("front_side", as_jsonable(credentials.front_side.value())); + } + if (credentials.reverse_side) { + o("reverse_side", as_jsonable(credentials.reverse_side.value())); + } if (credentials.selfie && with_selfie) { o("selfie", as_jsonable(credentials.selfie.value())); } diff --git a/td/telegram/SecureValue.h b/td/telegram/SecureValue.h index 9556c4b1..6a13779c 100644 --- a/td/telegram/SecureValue.h +++ b/td/telegram/SecureValue.h @@ -29,10 +29,13 @@ enum class SecureValueType : int32 { Passport, DriverLicense, IdentityCard, + InternalPassport, Address, UtilityBill, BankStatement, RentalAgreement, + PassportRegistration, + TemporaryRegistration, PhoneNumber, EmailAddress }; @@ -106,6 +109,8 @@ struct EncryptedSecureValue { SecureValueType type = SecureValueType::None; EncryptedSecureData data; vector files; + EncryptedSecureFile front_side; + EncryptedSecureFile reverse_side; EncryptedSecureFile selfie; string hash; // memory only }; @@ -123,7 +128,7 @@ td_api::object_ptr get_encrypted_passport_data_ob const EncryptedSecureValue &value); telegram_api::object_ptr get_input_secure_value_object( FileManager *file_manager, const EncryptedSecureValue &value, vector &input_files, - optional &selfie); + optional &front_side, optional &reverse_side, optional &selfie); vector> get_encrypted_passport_data_object( FileManager *file_manager, const vector &values); @@ -159,6 +164,8 @@ struct SecureValueCredentials { string hash; optional data; std::vector files; + optional front_side; + optional reverse_side; optional selfie; }; @@ -170,6 +177,8 @@ class SecureValue { SecureValueType type = SecureValueType::None; string data; vector files; + DatedFile front_side; + DatedFile reverse_side; DatedFile selfie; }; diff --git a/td/telegram/SecureValue.hpp b/td/telegram/SecureValue.hpp index 15b36326..dcba15ce 100644 --- a/td/telegram/SecureValue.hpp +++ b/td/telegram/SecureValue.hpp @@ -72,10 +72,14 @@ template void store(const EncryptedSecureValue &value, StorerT &storer) { bool has_data_hash = !value.data.hash.empty(); bool has_files = !value.files.empty(); + bool has_front_side = value.front_side.file.file_id.is_valid(); + bool has_reverse_side = value.reverse_side.file.file_id.is_valid(); bool has_selfie = value.selfie.file.file_id.is_valid(); BEGIN_STORE_FLAGS(); STORE_FLAG(has_data_hash); STORE_FLAG(has_files); + STORE_FLAG(has_front_side); + STORE_FLAG(has_reverse_side); STORE_FLAG(has_selfie); END_STORE_FLAGS(); store(value.type, storer); @@ -87,6 +91,12 @@ void store(const EncryptedSecureValue &value, StorerT &storer) { if (has_files) { store(value.files, storer); } + if (has_front_side) { + store(value.front_side, storer); + } + if (has_reverse_side) { + store(value.reverse_side, storer); + } if (has_selfie) { store(value.selfie, storer); } @@ -96,10 +106,14 @@ template void parse(EncryptedSecureValue &value, ParserT &parser) { bool has_data_hash; bool has_files; + bool has_front_side; + bool has_reverse_side; bool has_selfie; BEGIN_PARSE_FLAGS(); PARSE_FLAG(has_data_hash); PARSE_FLAG(has_files); + PARSE_FLAG(has_front_side); + PARSE_FLAG(has_reverse_side); PARSE_FLAG(has_selfie); END_PARSE_FLAGS(); parse(value.type, parser); @@ -111,6 +125,12 @@ void parse(EncryptedSecureValue &value, ParserT &parser) { if (has_files) { parse(value.files, parser); } + if (has_front_side) { + parse(value.front_side, parser); + } + if (has_reverse_side) { + parse(value.reverse_side, parser); + } if (has_selfie) { parse(value.selfie, parser); } diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 09b6fdd8..ad38692b 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -968,12 +968,21 @@ class CliClient final : public Actor { if (passport_data_type == "dl") { return make_tl_object(); } + if (passport_data_type == "ip") { + return make_tl_object(); + } if (passport_data_type == "ic") { return make_tl_object(); } if (passport_data_type == "ra") { return make_tl_object(); } + if (passport_data_type == "pr") { + return make_tl_object(); + } + if (passport_data_type == "tr") { + return make_tl_object(); + } return make_tl_object(); } @@ -1005,13 +1014,23 @@ class CliClient final : public Actor { return make_tl_object(arg); } else if (passport_data_type == "pd") { return make_tl_object(make_tl_object( - "Mike", "Towers", make_tl_object(29, 2, 2000), "male", "US")); + "Mike", "Towers", make_tl_object(29, 2, 2000), "male", "US", "GB")); } else if (passport_data_type == "driver_license" || passport_data_type == "dl") { - return make_tl_object(make_tl_object( - "1234567890", make_tl_object(1, 3, 2029), std::move(input_files), std::move(selfie))); + if (input_files.size() == 2) { + return make_tl_object(make_tl_object( + "1234567890", make_tl_object(1, 3, 2029), std::move(input_files[0]), + std::move(input_files[1]), std::move(selfie))); + } } else if (passport_data_type == "identity_card" || passport_data_type == "ic") { - return make_tl_object(make_tl_object( - "1234567890", nullptr, std::move(input_files), std::move(selfie))); + if (input_files.size() == 2) { + return make_tl_object(make_tl_object( + "1234567890", nullptr, std::move(input_files[0]), std::move(input_files[1]), std::move(selfie))); + } + } else if (passport_data_type == "internal_passport" || passport_data_type == "ip") { + if (input_files.size() == 1) { + return make_tl_object(make_tl_object( + "1234567890", nullptr, std::move(input_files[0]), nullptr, std::move(selfie))); + } } else if (passport_data_type == "rental_aggrement" || passport_data_type == "ra") { return make_tl_object(std::move(input_files)); }