Support translation for Telegram Passport personal documents.

GitOrigin-RevId: b54a7193e584b631ca6d9aeb132be72e02e5f87f
This commit is contained in:
levlam 2018-08-14 16:17:47 +03:00
parent 55417e88fd
commit 712d6bea89
5 changed files with 93 additions and 57 deletions

View File

@ -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 //@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<datedFile> = IdentityDocument; identityDocument number:string expiry_date:date front_side:datedFile reverse_side:datedFile selfie:datedFile translation:vector<datedFile> = 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 //@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<InputFile> = InputIdentityDocument; inputIdentityDocument number:string expiry_date:date front_side:InputFile reverse_side:InputFile selfie:InputFile translation:vector<InputFile> = 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<datedFile> translation:vector<datedFile> = 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<InputFile> translation:vector<InputFile> = InputPersonalDocument;
//@class PassportElement @description Contains information about a Telegram Passport element //@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 //@description A Telegram Passport element containing the user's address @address Address
passportElementAddress address:address = PassportElement; passportElementAddress address:address = PassportElement;
//@description A Telegram Passport element containing the user's utility bill @files List of files with the utility bill //@description A Telegram Passport element containing the user's utility bill @utility_bill Utility bill
passportElementUtilityBill files:vector<datedFile> = PassportElement; passportElementUtilityBill utility_bill:personalDocument = PassportElement;
//@description A Telegram Passport element containing the user's bank statement @files List of files with the bank statement //@description A Telegram Passport element containing the user's bank statement @bank_statement Bank statement
passportElementBankStatement files:vector<datedFile> = PassportElement; passportElementBankStatement bank_statement:personalDocument = PassportElement;
//@description A Telegram Passport element containing the user's rental agreement @files List of files with the rental agreement //@description A Telegram Passport element containing the user's rental agreement @rental_agreement Rental agreement
passportElementRentalAgreement files:vector<datedFile> = PassportElement; 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 //@description A Telegram Passport element containing the user's passport registration pages @passport_registration Passport registration pages
passportElementPassportRegistration files:vector<datedFile> = PassportElement; passportElementPassportRegistration passport_registration:personalDocument = PassportElement;
//@description A Telegram Passport element containing the user's temporary registration @files List of files with the temporary registration //@description A Telegram Passport element containing the user's temporary registration @temporary_registration Temporary registration
passportElementTemporaryRegistration files:vector<datedFile> = PassportElement; passportElementTemporaryRegistration temporary_registration:personalDocument = PassportElement;
//@description A Telegram Passport element containing the user's phone number @phone_number Phone number //@description A Telegram Passport element containing the user's phone number @phone_number Phone number
passportElementPhoneNumber phone_number:string = PassportElement; 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 //@description A Telegram Passport element to be saved containing the user's address @address The address to be saved
inputPassportElementAddress address:address = InputPassportElement; 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 //@description A Telegram Passport element to be saved containing the user's utility bill @utility_bill The utility bill to be saved
inputPassportElementUtilityBill files:vector<InputFile> = InputPassportElement; 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 //@description A Telegram Passport element to be saved containing the user's bank statement @bank_statement The bank statement to be saved
inputPassportElementBankStatement files:vector<InputFile> = InputPassportElement; 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 //@description A Telegram Passport element to be saved containing the user's rental agreement @rental_agreement The rental agreement to be saved
inputPassportElementRentalAgreement files:vector<InputFile> = InputPassportElement; 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 //@description A Telegram Passport element to be saved containing the user's passport registration @passport_registration The passport registration pages to be saved
inputPassportElementPassportRegistration files:vector<InputFile> = InputPassportElement; 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 //@description A Telegram Passport element to be saved containing the user's temporary registration @temporary_registration The temporary registration to be saved
inputPassportElementTemporaryRegistration files:vector<InputFile> = InputPassportElement; 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 //@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; 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 //@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; 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 //@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 //@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; 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 //@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

Binary file not shown.

View File

@ -413,7 +413,6 @@ void SetSecureValue::start_up() {
} }
} }
CHECK(secure_value_.files.empty() || secure_value_.translations.empty());
if (!secure_value_.files.empty()) { if (!secure_value_.files.empty()) {
CHECK(!front_side_file_id.is_valid()); CHECK(!front_side_file_id.is_valid());
CHECK(!reverse_side_file_id.is_valid()); CHECK(!reverse_side_file_id.is_valid());
@ -444,6 +443,12 @@ void SetSecureValue::start_up() {
break; 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) { if (is_duplicate) {
it = secure_value_.translations.erase(it); it = secure_value_.translations.erase(it);
} else { } else {

View File

@ -409,6 +409,11 @@ static td_api::object_ptr<td_api::datedFile> get_dated_file_object(FileManager *
return td_api::make_object<td_api::datedFile>(file_manager->get_file_object(file.file_id), file.date); return td_api::make_object<td_api::datedFile>(file_manager->get_file_object(file.file_id), file.date);
} }
static vector<td_api::object_ptr<td_api::datedFile>> get_dated_files_object(FileManager *file_manager,
const vector<DatedFile> &files) {
return transform(files, [file_manager](const DatedFile &file) { return get_dated_file_object(file_manager, file); });
}
static td_api::object_ptr<td_api::datedFile> get_dated_file_object(FileManager *file_manager, static td_api::object_ptr<td_api::datedFile> get_dated_file_object(FileManager *file_manager,
const EncryptedSecureFile &file) { const EncryptedSecureFile &file) {
DatedFile dated_file = file.file; DatedFile dated_file = file.file;
@ -502,8 +507,7 @@ static bool check_encrypted_secure_value(const EncryptedSecureValue &value) {
case SecureValueType::RentalAgreement: case SecureValueType::RentalAgreement:
case SecureValueType::PassportRegistration: case SecureValueType::PassportRegistration:
case SecureValueType::TemporaryRegistration: case SecureValueType::TemporaryRegistration:
return !has_encrypted_data && !has_plain_data && has_files && !has_front_side && !has_reverse_side && return !has_encrypted_data && !has_plain_data && has_files && !has_front_side && !has_reverse_side && !has_selfie;
!has_selfie && !has_translations;
case SecureValueType::PhoneNumber: case SecureValueType::PhoneNumber:
return has_plain_data && !has_files && !has_front_side && !has_reverse_side && !has_selfie && !has_translations; return has_plain_data && !has_files && !has_front_side && !has_reverse_side && !has_selfie && !has_translations;
case SecureValueType::EmailAddress: case SecureValueType::EmailAddress:
@ -941,13 +945,39 @@ static Result<td_api::object_ptr<td_api::identityDocument>> get_identity_documen
TRY_STATUS(check_document_number(number)); TRY_STATUS(check_document_number(number));
TRY_RESULT(date, get_date_object(expiry_date)); TRY_RESULT(date, get_date_object(expiry_date));
auto translations = transform( auto translations = get_dated_files_object(file_manager, value.translations);
value.translations, [file_manager](const DatedFile &file) { return get_dated_file_object(file_manager, file); });
return td_api::make_object<td_api::identityDocument>(std::move(number), std::move(date), std::move(front_side), return td_api::make_object<td_api::identityDocument>(std::move(number), std::move(date), std::move(front_side),
std::move(reverse_side), std::move(selfie), std::move(reverse_side), std::move(selfie),
std::move(translations)); std::move(translations));
} }
static Result<SecureValue> get_personal_document(
SecureValueType type, FileManager *file_manager,
td_api::object_ptr<td_api::inputPersonalDocument> &&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<td_api::personalDocument> get_personal_document_object(FileManager *file_manager,
const SecureValue &value) {
return td_api::make_object<td_api::personalDocument>(get_dated_files_object(file_manager, value.files),
get_dated_files_object(file_manager, value.translations));
}
static Status check_phone_number(string &phone_number) { static Status check_phone_number(string &phone_number) {
if (!clean_input_string(phone_number)) { if (!clean_input_string(phone_number)) {
return Status::Error(400, "Phone number must be encoded in UTF-8"); return Status::Error(400, "Phone number must be encoded in UTF-8");
@ -1004,38 +1034,25 @@ Result<SecureValue> get_secure_value(FileManager *file_manager,
} }
case td_api::inputPassportElementUtilityBill::ID: { case td_api::inputPassportElementUtilityBill::ID: {
auto input = td_api::move_object_as<td_api::inputPassportElementUtilityBill>(input_passport_element); auto input = td_api::move_object_as<td_api::inputPassportElementUtilityBill>(input_passport_element);
res.type = SecureValueType::UtilityBill; return get_personal_document(SecureValueType::UtilityBill, file_manager, std::move(input->utility_bill_));
TRY_RESULT(files, get_secure_files(file_manager, std::move(input->files_)));
res.files = std::move(files);
break;
} }
case td_api::inputPassportElementBankStatement::ID: { case td_api::inputPassportElementBankStatement::ID: {
auto input = td_api::move_object_as<td_api::inputPassportElementBankStatement>(input_passport_element); auto input = td_api::move_object_as<td_api::inputPassportElementBankStatement>(input_passport_element);
res.type = SecureValueType::BankStatement; return get_personal_document(SecureValueType::BankStatement, file_manager, std::move(input->bank_statement_));
TRY_RESULT(files, get_secure_files(file_manager, std::move(input->files_)));
res.files = std::move(files);
break;
} }
case td_api::inputPassportElementRentalAgreement::ID: { case td_api::inputPassportElementRentalAgreement::ID: {
auto input = td_api::move_object_as<td_api::inputPassportElementRentalAgreement>(input_passport_element); auto input = td_api::move_object_as<td_api::inputPassportElementRentalAgreement>(input_passport_element);
res.type = SecureValueType::RentalAgreement; return get_personal_document(SecureValueType::RentalAgreement, file_manager, std::move(input->rental_agreement_));
TRY_RESULT(files, get_secure_files(file_manager, std::move(input->files_)));
res.files = std::move(files);
break;
} }
case td_api::inputPassportElementPassportRegistration::ID: { case td_api::inputPassportElementPassportRegistration::ID: {
auto input = td_api::move_object_as<td_api::inputPassportElementPassportRegistration>(input_passport_element); auto input = td_api::move_object_as<td_api::inputPassportElementPassportRegistration>(input_passport_element);
res.type = SecureValueType::PassportRegistration; return get_personal_document(SecureValueType::PassportRegistration, file_manager,
TRY_RESULT(files, get_secure_files(file_manager, std::move(input->files_))); std::move(input->passport_registration_));
res.files = std::move(files);
break;
} }
case td_api::inputPassportElementTemporaryRegistration::ID: { case td_api::inputPassportElementTemporaryRegistration::ID: {
auto input = td_api::move_object_as<td_api::inputPassportElementTemporaryRegistration>(input_passport_element); auto input = td_api::move_object_as<td_api::inputPassportElementTemporaryRegistration>(input_passport_element);
res.type = SecureValueType::TemporaryRegistration; return get_personal_document(SecureValueType::TemporaryRegistration, file_manager,
TRY_RESULT(files, get_secure_files(file_manager, std::move(input->files_))); std::move(input->temporary_registration_));
res.files = std::move(files);
break;
} }
case td_api::inputPassportElementPhoneNumber::ID: { case td_api::inputPassportElementPhoneNumber::ID: {
auto input = td_api::move_object_as<td_api::inputPassportElementPhoneNumber>(input_passport_element); auto input = td_api::move_object_as<td_api::inputPassportElementPhoneNumber>(input_passport_element);
@ -1089,22 +1106,21 @@ Result<td_api::object_ptr<td_api::PassportElement>> get_passport_element_object(
case SecureValueType::RentalAgreement: case SecureValueType::RentalAgreement:
case SecureValueType::PassportRegistration: case SecureValueType::PassportRegistration:
case SecureValueType::TemporaryRegistration: { case SecureValueType::TemporaryRegistration: {
auto files = transform( auto document = get_personal_document_object(file_manager, value);
value.files, [file_manager](const DatedFile &file) { return get_dated_file_object(file_manager, file); });
if (value.type == SecureValueType::UtilityBill) { if (value.type == SecureValueType::UtilityBill) {
return td_api::make_object<td_api::passportElementUtilityBill>(std::move(files)); return td_api::make_object<td_api::passportElementUtilityBill>(std::move(document));
} }
if (value.type == SecureValueType::BankStatement) { if (value.type == SecureValueType::BankStatement) {
return td_api::make_object<td_api::passportElementBankStatement>(std::move(files)); return td_api::make_object<td_api::passportElementBankStatement>(std::move(document));
} }
if (value.type == SecureValueType::RentalAgreement) { if (value.type == SecureValueType::RentalAgreement) {
return td_api::make_object<td_api::passportElementRentalAgreement>(std::move(files)); return td_api::make_object<td_api::passportElementRentalAgreement>(std::move(document));
} }
if (value.type == SecureValueType::PassportRegistration) { if (value.type == SecureValueType::PassportRegistration) {
return td_api::make_object<td_api::passportElementPassportRegistration>(std::move(files)); return td_api::make_object<td_api::passportElementPassportRegistration>(std::move(document));
} }
if (value.type == SecureValueType::TemporaryRegistration) { if (value.type == SecureValueType::TemporaryRegistration) {
return td_api::make_object<td_api::passportElementTemporaryRegistration>(std::move(files)); return td_api::make_object<td_api::passportElementTemporaryRegistration>(std::move(document));
} }
UNREACHABLE(); UNREACHABLE();
break; break;
@ -1199,6 +1215,9 @@ Result<SecureValueWithCredentials> decrypt_secure_value(FileManager *file_manage
TRY_RESULT(files, decrypt_secure_files(file_manager, secret, encrypted_secure_value.files)); TRY_RESULT(files, decrypt_secure_files(file_manager, secret, encrypted_secure_value.files));
res.files = std::move(files.first); res.files = std::move(files.first);
res_credentials.files = std::move(files.second); 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; break;
} }
default: { default: {
@ -1330,6 +1349,7 @@ EncryptedSecureValue encrypt_secure_value(FileManager *file_manager, const secur
case SecureValueType::TemporaryRegistration: { case SecureValueType::TemporaryRegistration: {
string to_hash; string to_hash;
res.files = encrypt_secure_files(file_manager, master_secret, secure_value.files, 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(); res.hash = secure_storage::calc_value_hash(to_hash).as_slice().str();
break; break;
} }

View File

@ -1123,8 +1123,13 @@ class CliClient final : public Actor {
make_tl_object<td_api::inputIdentityDocument>("1234567890", nullptr, std::move(front_side), nullptr, make_tl_object<td_api::inputIdentityDocument>("1234567890", nullptr, std::move(front_side), nullptr,
std::move(selfie), std::move(input_files))); std::move(selfie), std::move(input_files)));
} }
} else if (passport_element_type == "rental_aggrement" || passport_element_type == "ra") { } else if (passport_element_type == "rental_agreement" || passport_element_type == "ra") {
return make_tl_object<td_api::inputPassportElementRentalAgreement>(std::move(input_files)); vector<td_api::object_ptr<td_api::InputFile>> translation;
if (selfie != nullptr) {
translation.push_back(std::move(selfie));
}
return make_tl_object<td_api::inputPassportElementRentalAgreement>(
make_tl_object<td_api::inputPersonalDocument>(std::move(input_files), std::move(translation)));
} }
LOG(ERROR) << "Unsupported passport element type " << passport_element_type; LOG(ERROR) << "Unsupported passport element type " << passport_element_type;