From 712d6bea89eeb53be0c1d21883cfe0c6d5dcb150 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 14 Aug 2018 16:17:47 +0300 Subject: [PATCH] Support translation for Telegram Passport personal documents. GitOrigin-RevId: b54a7193e584b631ca6d9aeb132be72e02e5f87f --- td/generate/scheme/td_api.tl | 52 +++++++++++---------- td/generate/scheme/td_api.tlo | Bin 132836 -> 133196 bytes td/telegram/SecureManager.cpp | 7 ++- td/telegram/SecureValue.cpp | 82 +++++++++++++++++++++------------- td/telegram/cli.cpp | 9 +++- 5 files changed, 93 insertions(+), 57 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index e703b67c..6f73d799 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -883,10 +883,16 @@ personalDetails first_name:string middle_name:string last_name:string native_fir //@reverse_side Reverse side of the document; only for driver license and identity card @selfie Selfie with the document; may be null @translation List of files with the document translation identityDocument number:string expiry_date:date front_side:datedFile reverse_side:datedFile selfie:datedFile translation:vector = IdentityDocument; -//@description An identity document to be saved @number Document number; 1-24 characters @expiry_date Document expiry date, if available @front_side Front side of the document +//@description An identity document to be saved to Telegram Passport @number Document number; 1-24 characters @expiry_date Document expiry date, if available @front_side Front side of the document //@reverse_side Reverse side of the document; only for driver license and identity card @selfie Selfie with the document, if available @translation List of files with the document translation inputIdentityDocument number:string expiry_date:date front_side:InputFile reverse_side:InputFile selfie:InputFile translation:vector = InputIdentityDocument; +//@description A personal document, containing some information about a user @files List of files with the document @translation List of files with the document translation +personalDocument files:vector translation:vector = PersonalDocument; + +//@description A personal document to be saved to Telegram Passport @files List of files with the document @translation List of files with the document translation +inputPersonalDocument files:vector translation:vector = InputPersonalDocument; + //@class PassportElement @description Contains information about a Telegram Passport element @@ -908,20 +914,20 @@ passportElementInternalPassport internal_passport:identityDocument = PassportEle //@description A Telegram Passport element containing the user's address @address Address passportElementAddress address:address = PassportElement; -//@description A Telegram Passport element containing the user's utility bill @files List of files with the utility bill -passportElementUtilityBill files:vector = PassportElement; +//@description A Telegram Passport element containing the user's utility bill @utility_bill Utility bill +passportElementUtilityBill utility_bill:personalDocument = PassportElement; -//@description A Telegram Passport element containing the user's bank statement @files List of files with the bank statement -passportElementBankStatement files:vector = PassportElement; +//@description A Telegram Passport element containing the user's bank statement @bank_statement Bank statement +passportElementBankStatement bank_statement:personalDocument = PassportElement; -//@description A Telegram Passport element containing the user's rental agreement @files List of files with the rental agreement -passportElementRentalAgreement files:vector = PassportElement; +//@description A Telegram Passport element containing the user's rental agreement @rental_agreement Rental agreement +passportElementRentalAgreement rental_agreement:personalDocument = PassportElement; -//@description A Telegram Passport element containing the user's passport registration pages @files List of files with the passport registration pages -passportElementPassportRegistration files:vector = PassportElement; +//@description A Telegram Passport element containing the user's passport registration pages @passport_registration Passport registration pages +passportElementPassportRegistration passport_registration:personalDocument = PassportElement; -//@description A Telegram Passport element containing the user's temporary registration @files List of files with the temporary registration -passportElementTemporaryRegistration files:vector = PassportElement; +//@description A Telegram Passport element containing the user's temporary registration @temporary_registration Temporary registration +passportElementTemporaryRegistration temporary_registration:personalDocument = PassportElement; //@description A Telegram Passport element containing the user's phone number @phone_number Phone number passportElementPhoneNumber phone_number:string = PassportElement; @@ -950,20 +956,20 @@ inputPassportElementInternalPassport internal_passport:inputIdentityDocument = I //@description A Telegram Passport element to be saved containing the user's address @address The address to be saved inputPassportElementAddress address:address = InputPassportElement; -//@description A Telegram Passport element to be saved containing the user's utility bill @files List of files with the utility bill -inputPassportElementUtilityBill files:vector = InputPassportElement; +//@description A Telegram Passport element to be saved containing the user's utility bill @utility_bill The utility bill to be saved +inputPassportElementUtilityBill utility_bill:inputPersonalDocument = InputPassportElement; -//@description A Telegram Passport element to be saved containing the user's bank statement @files List of files with the bank statement -inputPassportElementBankStatement files:vector = InputPassportElement; +//@description A Telegram Passport element to be saved containing the user's bank statement @bank_statement The bank statement to be saved +inputPassportElementBankStatement bank_statement:inputPersonalDocument = InputPassportElement; -//@description A Telegram Passport element to be saved containing the user's rental agreement @files List of files with the rental agreement -inputPassportElementRentalAgreement files:vector = InputPassportElement; +//@description A Telegram Passport element to be saved containing the user's rental agreement @rental_agreement The rental agreement to be saved +inputPassportElementRentalAgreement rental_agreement:inputPersonalDocument = InputPassportElement; -//@description A Telegram Passport element to be saved containing the user's passport registration @files List of files with the passport registration -inputPassportElementPassportRegistration files:vector = InputPassportElement; +//@description A Telegram Passport element to be saved containing the user's passport registration @passport_registration The passport registration pages to be saved +inputPassportElementPassportRegistration passport_registration:inputPersonalDocument = InputPassportElement; -//@description A Telegram Passport element to be saved containing the user's temporary registration @files List of files with the temporary registration -inputPassportElementTemporaryRegistration files:vector = InputPassportElement; +//@description A Telegram Passport element to be saved containing the user's temporary registration @temporary_registration The temporary registration to be saved +inputPassportElementTemporaryRegistration temporary_registration:inputPersonalDocument = InputPassportElement; //@description A Telegram Passport element to be saved containing the user's phone number @phone_number The phone number to be saved inputPassportElementPhoneNumber phone_number:string = InputPassportElement; @@ -1011,7 +1017,7 @@ passportElementError type:PassportElementType message:string source:PassportElem //@description Contains information about a Telegram Passport element that was requested by a service @type Type of the element @is_selfie_required True, if a selfie is required with the identity document -//@is_translation_required True, if a translation is required with the identity document @is_native_name_required True, if a native name is required with the personal details +//@is_translation_required True, if a translation is required with the document @is_native_name_required True, if a native name is required with the personal details passportSuitableElement type:PassportElementType is_selfie_required:Bool is_translation_required:Bool is_native_name_required:Bool = PassportSuitableElement; //@description Contains description of required Telegram Passport element that was requested by a service @suitable_elements List of Telegram Passport elements any of which is enough to provide @@ -1033,7 +1039,7 @@ encryptedPassportElement type:PassportElementType data:bytes front_side:datedFil //@class InputPassportElementErrorSource @description Contains the description of an error in Telegram Passport element; for bots only -//@description The element contains an error in an unspecified place. The error will be considered resolved when anything changes @element_hash Current hash of the whole element +//@description The element contains an error in an unspecified place. The error will be considered resolved when new data is added @element_hash Current hash of the whole element inputPassportElementErrorSourceUnspecified element_hash:bytes = InputPassportElementErrorSource; //@description A data field contains an error. The error is considered resolved when the field's value changes @field_name Field name @data_hash Current data hash diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index f1685a8bc68bee8edb527b606c0b5015f9846a1d..36278f27619a36498fe019a45c9130c8f74896f1 100644 GIT binary patch delta 1513 zcmaFT%W-A`2k)cV`c@23aB3rOG%xGko5~F$lNa)eOm5`umt0l-C0W!nub{LfAhoDC zKQA%IB|o_|H#Ki^BA4`L0lpMg7QV}|KQ>ngXE5^n6T6U!Z@4C8B{vvt;*yxFwrN=EFjVf z%c15aEZ2dEOjvFp3bG33tE+NcF^vpf+=q7iBXZ@QTutEjHP`;$ZyzKbmlEji! zU}%+q4I$Q0?K#!ylP|1L2|;(MKoQWW#GLrV^rBRRu?!5v8XT}7%5QSON}Wh_gGCDx zi;D~Li%Q~)QqwbwONtUpGV}AmjwaghhrZu>HNk=WcBQxnx(#B$Z~$76SX7B=1wQ9b z4p;?EC;}g$aeiPGG)dGzMK+tPHegi+C)G?WNfj9QAURN!GfiIjPJ8l(l{}Lt%x9VW zp~Z#;B(phUgNQXa9ZxQJy#&GlB~(z#o*eN;1Hx!|V*+99d1C-!e0XC4Vd%WofiPm; zLPci0g{o0lt}%JZ8xe>!&pW7Dz(gtnG941a3=E(|dP$b$)8v|WGC?2-V$vrlyP>B~ zbVDjJX=8x4fHN@LnMV-B5f9??{gtYo7@8*deTh zpD`SYAhQGtPzzL05djj1B~$as7cwm-UwF^K0utT6fsxT;3)qP1f3`A)fLYr^wlSJO blIirGPmD6)vYTPLBP*jZSbq7FPmCe}5OgVW delta 994 zcmX>zf#XRp2k)cV`c@23aAG5GG%xGIzOW3D$qRW!CO7i-Z+78JVP*Mlwd~yHHNqK8 zn_a{Lco-8lPgRm`W&tUj^wtJUPyVvh0K&+5t1#JPnFxfFu*?L)n6b(w1wSrL7*?@9+aIC~vPvQ-HLoNw$1%MqH8mH= z#9=Fj0fl|dXEnfXUAa=6Xlqx>-?^g+)}^}&r!GhU^{j%1`hiu@(EPIs65`Vx9x+0M zHW#cmVBPGqk;9r56pswk=YC<-pWN}L1RSlP2m}dFc6h4+VdT6ufiRZ5HGnW~ytRNZ zMBeE@7(B~WCTF}8fp8k$LDg+}2Q}-HfY`;R1ivc7D zk3RG1Jj}qTLsy?QYlZpb3-1*;iBZfOoy|Yl;R9C1q8KK}hiWKK4ty&<`OF6%qKv501;^}#xq J`+Q*(0RYJse9!;@ diff --git a/td/telegram/SecureManager.cpp b/td/telegram/SecureManager.cpp index eb60a7eb..eb4015c6 100644 --- a/td/telegram/SecureManager.cpp +++ b/td/telegram/SecureManager.cpp @@ -413,7 +413,6 @@ void SetSecureValue::start_up() { } } - CHECK(secure_value_.files.empty() || secure_value_.translations.empty()); if (!secure_value_.files.empty()) { CHECK(!front_side_file_id.is_valid()); CHECK(!reverse_side_file_id.is_valid()); @@ -444,6 +443,12 @@ void SetSecureValue::start_up() { break; } } + for (auto &dated_file : secure_value_.files) { + if (file_id == file_manager->get_file_view(dated_file.file_id).file_id()) { + is_duplicate = true; + break; + } + } if (is_duplicate) { it = secure_value_.translations.erase(it); } else { diff --git a/td/telegram/SecureValue.cpp b/td/telegram/SecureValue.cpp index 1d2a53dd..35e90042 100644 --- a/td/telegram/SecureValue.cpp +++ b/td/telegram/SecureValue.cpp @@ -409,6 +409,11 @@ static td_api::object_ptr get_dated_file_object(FileManager * return td_api::make_object(file_manager->get_file_object(file.file_id), file.date); } +static vector> get_dated_files_object(FileManager *file_manager, + const vector &files) { + return transform(files, [file_manager](const DatedFile &file) { return get_dated_file_object(file_manager, file); }); +} + static td_api::object_ptr get_dated_file_object(FileManager *file_manager, const EncryptedSecureFile &file) { DatedFile dated_file = file.file; @@ -502,8 +507,7 @@ static bool check_encrypted_secure_value(const EncryptedSecureValue &value) { 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 && !has_translations; + 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 && !has_translations; case SecureValueType::EmailAddress: @@ -941,13 +945,39 @@ static Result> get_identity_documen TRY_STATUS(check_document_number(number)); TRY_RESULT(date, get_date_object(expiry_date)); - auto translations = transform( - value.translations, [file_manager](const DatedFile &file) { return get_dated_file_object(file_manager, file); }); + auto translations = get_dated_files_object(file_manager, value.translations); return td_api::make_object(std::move(number), std::move(date), std::move(front_side), std::move(reverse_side), std::move(selfie), std::move(translations)); } +static Result get_personal_document( + SecureValueType type, FileManager *file_manager, + td_api::object_ptr &&personal_document) { + if (personal_document == nullptr) { + return Status::Error(400, "Personal document must not be empty"); + } + + SecureValue res; + res.type = type; + if (personal_document->files_.empty()) { + return Status::Error(400, "Document's files are required"); + } + TRY_RESULT(files, get_secure_files(file_manager, std::move(personal_document->files_))); + res.files = std::move(files); + if (!personal_document->translation_.empty()) { + TRY_RESULT(translations, get_secure_files(file_manager, std::move(personal_document->translation_))); + res.translations = std::move(translations); + } + return res; +} + +static td_api::object_ptr get_personal_document_object(FileManager *file_manager, + const SecureValue &value) { + return td_api::make_object(get_dated_files_object(file_manager, value.files), + get_dated_files_object(file_manager, value.translations)); +} + 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"); @@ -1004,38 +1034,25 @@ Result get_secure_value(FileManager *file_manager, } case td_api::inputPassportElementUtilityBill::ID: { auto input = td_api::move_object_as(input_passport_element); - res.type = SecureValueType::UtilityBill; - TRY_RESULT(files, get_secure_files(file_manager, std::move(input->files_))); - res.files = std::move(files); - break; + return get_personal_document(SecureValueType::UtilityBill, file_manager, std::move(input->utility_bill_)); } case td_api::inputPassportElementBankStatement::ID: { auto input = td_api::move_object_as(input_passport_element); - res.type = SecureValueType::BankStatement; - TRY_RESULT(files, get_secure_files(file_manager, std::move(input->files_))); - res.files = std::move(files); - break; + return get_personal_document(SecureValueType::BankStatement, file_manager, std::move(input->bank_statement_)); } case td_api::inputPassportElementRentalAgreement::ID: { auto input = td_api::move_object_as(input_passport_element); - res.type = SecureValueType::RentalAgreement; - TRY_RESULT(files, get_secure_files(file_manager, std::move(input->files_))); - res.files = std::move(files); - break; + return get_personal_document(SecureValueType::RentalAgreement, file_manager, std::move(input->rental_agreement_)); } case td_api::inputPassportElementPassportRegistration::ID: { auto input = td_api::move_object_as(input_passport_element); - res.type = SecureValueType::PassportRegistration; - TRY_RESULT(files, get_secure_files(file_manager, std::move(input->files_))); - res.files = std::move(files); - break; + return get_personal_document(SecureValueType::PassportRegistration, file_manager, + std::move(input->passport_registration_)); } case td_api::inputPassportElementTemporaryRegistration::ID: { auto input = td_api::move_object_as(input_passport_element); - res.type = SecureValueType::TemporaryRegistration; - TRY_RESULT(files, get_secure_files(file_manager, std::move(input->files_))); - res.files = std::move(files); - break; + return get_personal_document(SecureValueType::TemporaryRegistration, file_manager, + std::move(input->temporary_registration_)); } case td_api::inputPassportElementPhoneNumber::ID: { auto input = td_api::move_object_as(input_passport_element); @@ -1089,22 +1106,21 @@ Result> get_passport_element_object( 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); }); + auto document = get_personal_document_object(file_manager, value); if (value.type == SecureValueType::UtilityBill) { - return td_api::make_object(std::move(files)); + return td_api::make_object(std::move(document)); } if (value.type == SecureValueType::BankStatement) { - return td_api::make_object(std::move(files)); + return td_api::make_object(std::move(document)); } if (value.type == SecureValueType::RentalAgreement) { - return td_api::make_object(std::move(files)); + return td_api::make_object(std::move(document)); } if (value.type == SecureValueType::PassportRegistration) { - return td_api::make_object(std::move(files)); + return td_api::make_object(std::move(document)); } if (value.type == SecureValueType::TemporaryRegistration) { - return td_api::make_object(std::move(files)); + return td_api::make_object(std::move(document)); } UNREACHABLE(); break; @@ -1199,6 +1215,9 @@ Result decrypt_secure_value(FileManager *file_manage 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); + TRY_RESULT(translations, decrypt_secure_files(file_manager, secret, encrypted_secure_value.translations)); + res.translations = std::move(translations.first); + res_credentials.translations = std::move(translations.second); break; } default: { @@ -1330,6 +1349,7 @@ EncryptedSecureValue encrypt_secure_value(FileManager *file_manager, const secur case SecureValueType::TemporaryRegistration: { string to_hash; res.files = encrypt_secure_files(file_manager, master_secret, secure_value.files, to_hash); + res.translations = encrypt_secure_files(file_manager, master_secret, secure_value.translations, to_hash); res.hash = secure_storage::calc_value_hash(to_hash).as_slice().str(); break; } diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 2785c4a8..decf4154 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -1123,8 +1123,13 @@ class CliClient final : public Actor { make_tl_object("1234567890", nullptr, std::move(front_side), nullptr, std::move(selfie), std::move(input_files))); } - } else if (passport_element_type == "rental_aggrement" || passport_element_type == "ra") { - return make_tl_object(std::move(input_files)); + } else if (passport_element_type == "rental_agreement" || passport_element_type == "ra") { + vector> translation; + if (selfie != nullptr) { + translation.push_back(std::move(selfie)); + } + return make_tl_object( + make_tl_object(std::move(input_files), std::move(translation))); } LOG(ERROR) << "Unsupported passport element type " << passport_element_type;