diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 92720968..818577ed 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -799,6 +799,10 @@ paymentResult success:Bool verification_url:string = PaymentResult; paymentReceipt date:int32 payments_provider_user_id:int32 invoice:invoice order_info:orderInfo shipping_option:shippingOption credentials_title:string = PaymentReceipt; +//@description File with the date it was uploaded @file The file @date Point in time (Unix timestamp) when the file was uploaded +datedFile file:file date:int32 = DatedFile; + + //@class PassportDataType @description Contains type of a Telegram Passport data //@description The Telegram Passport data contains a user's personal details @@ -840,7 +844,7 @@ date day:int32 month:int32 year:int32 = Date; personalDetails first_name:string last_name:string birthdate:date gender:string 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:file = IdentityDocument; +identityDocument number:string expiry_date:date files:vector 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 @selfie Selfie with the document, if available inputIdentityDocument number:string expiry_date:date files:vector selfie:InputFile = InputIdentityDocument; @@ -864,13 +868,13 @@ passportDataIdentityCard identity_card:identityDocument = PassportData; passportDataAddress address:address = PassportData; //@description The Telegram Passport data contains a user's utility bill @files List of files with the utility bill -passportDataUtilityBill files:vector = PassportData; +passportDataUtilityBill files:vector = PassportData; //@description The Telegram Passport data contains a user's bank statement @files List of files with the bank statement -passportDataBankStatement files:vector = PassportData; +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; +passportDataRentalAgreement files:vector = PassportData; //@description The Telegram Passport data contains a user's phone number @phone_number The phone number passportDataPhoneNumber phone_number:string = PassportData; @@ -946,7 +950,7 @@ 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:file = EncryptedPassportData; +encryptedPassportData type:PassportDataType data:bytes files:vector value:string selfie:datedFile = EncryptedPassportData; //@class InputPassportDataErrorSource @description Contains description of an error in a Telegram Passport data; for bots only diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index 9f8d06ad..2631df6c 100644 Binary files a/td/generate/scheme/td_api.tlo and b/td/generate/scheme/td_api.tlo differ diff --git a/td/telegram/SecureManager.cpp b/td/telegram/SecureManager.cpp index 3d0227dc..596f04ec 100644 --- a/td/telegram/SecureManager.cpp +++ b/td/telegram/SecureManager.cpp @@ -339,33 +339,34 @@ void SetSecureValue::start_up() { })); auto *file_manager = G()->td().get_actor_unsafe()->file_manager_.get(); - // Remove duplicated files + // Remove duplicate files + 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(); + } for (auto it = secure_value_.files.begin(); it != secure_value_.files.end();) { - bool is_duplicate = false; + 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_manager->get_file_view(*it).file_id() == file_manager->get_file_view(*pit).file_id()) { + if (file_id == file_manager->get_file_view(pit->file_id).file_id()) { is_duplicate = true; break; } } - if (secure_value_.selfie.is_valid() && - file_manager->get_file_view(*it).file_id() == file_manager->get_file_view(secure_value_.selfie).file_id()) { - is_duplicate = true; - } if (is_duplicate) { it = secure_value_.files.erase(it); } else { - it++; + ++it; } } to_upload_.resize(secure_value_.files.size()); upload_callback_ = std::make_shared(actor_id(this)); for (size_t i = 0; i < to_upload_.size(); i++) { - start_upload(file_manager, secure_value_.files[i], to_upload_[i]); + start_upload(file_manager, secure_value_.files[i].file_id, to_upload_[i]); } - if (selfie_) { - start_upload(file_manager, secure_value_.selfie, selfie_.value()); + if (secure_value_.selfie.file_id.is_valid()) { + start_upload(file_manager, secure_value_.selfie.file_id, selfie_.value()); } } @@ -414,10 +415,10 @@ void SetSecureValue::on_result(NetQueryPtr query) { return on_error(Status::Error("Different files count")); } for (size_t i = 0; i < secure_value_.files.size(); i++) { - merge(file_manager, secure_value_.files[i], encrypted_secure_value.files[i]); + merge(file_manager, secure_value_.files[i].file_id, encrypted_secure_value.files[i]); } - if (secure_value_.selfie.is_valid()) { - merge(file_manager, secure_value_.selfie, encrypted_secure_value.selfie); + if (secure_value_.selfie.file_id.is_valid()) { + merge(file_manager, secure_value_.selfie.file_id, encrypted_secure_value.selfie); } auto r_secure_value = decrypt_secure_value(file_manager, *secret_, encrypted_secure_value); if (r_secure_value.is_error()) { @@ -435,7 +436,7 @@ void SetSecureValue::merge(FileManager *file_manager, FileId file_id, EncryptedS LOG(ERROR) << "Hash mismatch"; return; } - auto status = file_manager->merge(encrypted_file.file_id, file_id); + auto status = file_manager->merge(encrypted_file.file.file_id, file_id); LOG_IF(ERROR, status.is_error()) << status.error(); } diff --git a/td/telegram/SecureValue.cpp b/td/telegram/SecureValue.cpp index 44dad72a..73d9ccef 100644 --- a/td/telegram/SecureValue.cpp +++ b/td/telegram/SecureValue.cpp @@ -8,6 +8,7 @@ #include "td/telegram/DialogId.h" #include "td/telegram/files/FileManager.h" +#include "td/telegram/Global.h" #include "td/telegram/misc.h" #include "td/telegram/Payments.h" @@ -246,9 +247,16 @@ string get_secure_value_data_field_name(SecureValueType type, string field_name) return string(); } +bool operator==(const DatedFile &lhs, const DatedFile &rhs) { + return lhs.file_id == rhs.file_id && lhs.date == rhs.date; +} + +bool operator!=(const DatedFile &lhs, const DatedFile &rhs) { + return !(lhs == rhs); +} + bool operator==(const EncryptedSecureFile &lhs, const EncryptedSecureFile &rhs) { - return lhs.file_id == rhs.file_id && lhs.date == rhs.date && lhs.file_hash == rhs.file_hash && - lhs.encrypted_secret == rhs.encrypted_secret; + return lhs.file == rhs.file && lhs.file_hash == rhs.file_hash && lhs.encrypted_secret == rhs.encrypted_secret; } bool operator!=(const EncryptedSecureFile &lhs, const EncryptedSecureFile &rhs) { @@ -269,13 +277,13 @@ EncryptedSecureFile get_encrypted_secure_file(FileManager *file_manager, LOG(ERROR) << "Wrong dc_id = " << dc_id; break; } - result.file_id = file_manager->register_remote( + result.file.file_id = file_manager->register_remote( FullRemoteFileLocation(FileType::Secure, secure_file->id_, secure_file->access_hash_, DcId::internal(dc_id)), FileLocationSource::FromServer, {}, 0, 0, ""); - result.date = secure_file->date_; - if (result.date < 0) { - LOG(ERROR) << "Receive wrong date " << result.date; - result.date = 0; + result.file.date = secure_file->date_; + if (result.file.date < 0) { + LOG(ERROR) << "Receive wrong date " << result.file.date; + result.file.date = 0; } result.encrypted_secret = secure_file->secret_.as_slice().str(); result.file_hash = secure_file->file_hash_.as_slice().str(); @@ -293,7 +301,7 @@ vector get_encrypted_secure_files(FileManager *file_manager results.reserve(secure_files.size()); for (auto &secure_file : secure_files) { auto result = get_encrypted_secure_file(file_manager, std::move(secure_file)); - if (result.file_id.is_valid()) { + if (result.file.file_id.is_valid()) { results.push_back(std::move(result)); } } @@ -303,11 +311,11 @@ vector get_encrypted_secure_files(FileManager *file_manager telegram_api::object_ptr get_input_secure_file_object(FileManager *file_manager, const EncryptedSecureFile &file, SecureInputFile &input_file) { - CHECK(file_manager->get_file_view(file.file_id).file_id() == + CHECK(file_manager->get_file_view(file.file.file_id).file_id() == file_manager->get_file_view(input_file.file_id).file_id()); auto res = std::move(input_file.input_file); if (res == nullptr) { - return file_manager->get_file_view(file.file_id).remote_location().as_input_secure_file(); + return file_manager->get_file_view(file.file.file_id).remote_location().as_input_secure_file(); } telegram_api::downcast_call(*res, overloaded( [&](telegram_api::inputSecureFileUploaded &uploaded) { @@ -318,20 +326,27 @@ telegram_api::object_ptr get_input_secure_file_ob return res; } -td_api::object_ptr get_encrypted_file_object(FileManager *file_manager, const EncryptedSecureFile &file) { - CHECK(file.file_id.is_valid()); - auto file_view = file_manager->get_file_view(file.file_id); - auto file_id = file_manager->register_remote( +static td_api::object_ptr get_dated_file_object(FileManager *file_manager, DatedFile file) { + return td_api::make_object(file_manager->get_file_object(file.file_id), file.date); +} + +static td_api::object_ptr get_dated_file_object(FileManager *file_manager, + const EncryptedSecureFile &file) { + DatedFile dated_file = file.file; + auto file_id = dated_file.file_id; + CHECK(file_id.is_valid()); + auto file_view = file_manager->get_file_view(file_id); + dated_file.file_id = file_manager->register_remote( FullRemoteFileLocation(FileType::SecureRaw, file_view.remote_location().get_id(), file_view.remote_location().get_access_hash(), file_view.remote_location().get_dc_id()), FileLocationSource::FromServer, {}, 0, 0, ""); - return file_manager->get_file_object(file_id); + return get_dated_file_object(file_manager, dated_file); } -vector> get_encrypted_files_object(FileManager *file_manager, - const vector &files) { +static vector> get_dated_files_object(FileManager *file_manager, + const vector &files) { return transform( - files, [file_manager](const EncryptedSecureFile &file) { return get_encrypted_file_object(file_manager, file); }); + files, [file_manager](const EncryptedSecureFile &file) { return get_dated_file_object(file_manager, file); }); } vector> get_input_secure_files_object( @@ -417,15 +432,15 @@ 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_encrypted_files_object(file_manager, value.files), is_plain ? value.data.data : string(), - value.selfie.file_id.is_valid() ? get_encrypted_file_object(file_manager, value.selfie) : nullptr); + 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); } telegram_api::object_ptr get_input_secure_value_object( FileManager *file_manager, const EncryptedSecureValue &value, std::vector &input_files, optional &selfie) { bool is_plain = value.type == SecureValueType::PhoneNumber || value.type == SecureValueType::EmailAddress; - bool has_selfie = value.selfie.file_id.is_valid(); + bool has_selfie = value.selfie.file.file_id.is_valid(); int32 flags = 0; tl_object_ptr plain_data; if (is_plain) { @@ -645,16 +660,21 @@ static Status check_document_number(string &number) { return Status::OK(); } -static Result get_secure_file(FileManager *file_manager, td_api::object_ptr &&file) { - return file_manager->get_input_file_id(FileType::Secure, std::move(file), DialogId(), false, false, false, true); +static Result get_secure_file(FileManager *file_manager, td_api::object_ptr &&file) { + TRY_RESULT(file_id, + file_manager->get_input_file_id(FileType::Secure, std::move(file), DialogId(), false, false, false, true)); + DatedFile result; + result.file_id = file_id; + result.date = G()->unix_time(); + return std::move(result); } -static Result> get_secure_files(FileManager *file_manager, - vector> &&files) { - vector result; +static Result> get_secure_files(FileManager *file_manager, + vector> &&files) { + vector result; for (auto &file : files) { - TRY_RESULT(file_id, get_secure_file(file_manager, std::move(file))); - result.push_back(file_id); + TRY_RESULT(dated_file, get_secure_file(file_manager, std::move(file))); + result.push_back(std::move(dated_file)); } return result; } @@ -678,19 +698,21 @@ static Result get_identity_document( res.files = std::move(files); if (identity_document->selfie_ != nullptr) { - TRY_RESULT(file_id, get_secure_file(file_manager, std::move(identity_document->selfie_))); - res.selfie = file_id; + TRY_RESULT(file, get_secure_file(file_manager, std::move(identity_document->selfie_))); + res.selfie = file; } return res; } static Result> get_identity_document_object(FileManager *file_manager, const SecureValue &value) { - auto files = transform(value.files, [file_manager](FileId id) { return file_manager->get_file_object(id); }); + auto files = transform(value.files, [file_manager](const DatedFile &dated_file) { + return get_dated_file_object(file_manager, dated_file); + }); - td_api::object_ptr selfie; - if (value.selfie.is_valid()) { - selfie = file_manager->get_file_object(value.selfie); + td_api::object_ptr selfie; + if (value.selfie.file_id.is_valid()) { + selfie = get_dated_file_object(file_manager, value.selfie); } auto data_copy = value.data; @@ -830,7 +852,8 @@ Result> get_passport_data_object(FileMa case SecureValueType::UtilityBill: case SecureValueType::BankStatement: case SecureValueType::RentalAgreement: { - auto files = transform(value.files, [file_manager](FileId id) { return file_manager->get_file_object(id); }); + auto files = transform( + value.files, [file_manager](const DatedFile &file) { return get_dated_file_object(file_manager, file); }); if (value.type == SecureValueType::UtilityBill) { return td_api::make_object(std::move(files)); } @@ -871,33 +894,33 @@ td_api::object_ptr get_all_passport_data_object(FileMan return td_api::make_object(std::move(result)); } -static Result> decrypt_secure_file(FileManager *file_manager, - const secure_storage::Secret &master_secret, - const EncryptedSecureFile &secure_file) { - if (!secure_file.file_id.is_valid()) { - return std::make_pair(FileId(), SecureFileCredentials()); +static Result> decrypt_secure_file( + FileManager *file_manager, const secure_storage::Secret &master_secret, const EncryptedSecureFile &secure_file) { + if (!secure_file.file.file_id.is_valid()) { + return std::make_pair(DatedFile(), SecureFileCredentials()); } TRY_RESULT(hash, secure_storage::ValueHash::create(secure_file.file_hash)); TRY_RESULT(encrypted_secret, secure_storage::EncryptedSecret::create(secure_file.encrypted_secret)); TRY_RESULT(secret, encrypted_secret.decrypt(PSLICE() << master_secret.as_slice() << hash.as_slice())); FileEncryptionKey key{secret}; key.set_value_hash(hash); - file_manager->set_encryption_key(secure_file.file_id, std::move(key)); - return std::make_pair(secure_file.file_id, SecureFileCredentials{secret.as_slice().str(), hash.as_slice().str()}); + file_manager->set_encryption_key(secure_file.file.file_id, std::move(key)); + return std::make_pair(secure_file.file, SecureFileCredentials{secret.as_slice().str(), hash.as_slice().str()}); } -static Result, vector>> decrypt_secure_files( +static Result, vector>> decrypt_secure_files( FileManager *file_manager, const secure_storage::Secret &secret, const vector &secure_files) { - vector res; + vector result; vector credentials; - res.reserve(secure_files.size()); + result.reserve(secure_files.size()); + credentials.reserve(secure_files.size()); for (auto &file : secure_files) { TRY_RESULT(decrypted_file, decrypt_secure_file(file_manager, secret, file)); - res.push_back(decrypted_file.first); - credentials.push_back(decrypted_file.second); + result.push_back(std::move(decrypted_file.first)); + credentials.push_back(std::move(decrypted_file.second)); } - return std::make_pair(std::move(res), std::move(credentials)); + return std::make_pair(std::move(result), std::move(credentials)); } static Result> decrypt_secure_data(const secure_storage::Secret &master_secret, @@ -932,7 +955,7 @@ Result decrypt_secure_value(FileManager *file_manage res_credentials.files = std::move(files.second); TRY_RESULT(selfie, decrypt_secure_file(file_manager, secret, encrypted_secure_value.selfie)); res.selfie = std::move(selfie.first); - if (res.selfie.is_valid()) { + if (res.selfie.file_id.is_valid()) { res_credentials.selfie = std::move(selfie.second); } break; @@ -958,8 +981,8 @@ Result> decrypt_secure_values( } static EncryptedSecureFile encrypt_secure_file(FileManager *file_manager, const secure_storage::Secret &master_secret, - FileId file, string &to_hash) { - auto file_view = file_manager->get_file_view(file); + DatedFile file, string &to_hash) { + auto file_view = file_manager->get_file_view(file.file_id); if (file_view.empty()) { return EncryptedSecureFile(); } @@ -974,7 +997,7 @@ static EncryptedSecureFile encrypt_secure_file(FileManager *file_manager, const auto value_hash = file_view.encryption_key().value_hash(); auto secret = file_view.encryption_key().secret(); EncryptedSecureFile res; - res.file_id = file; + res.file = file; res.file_hash = value_hash.as_slice().str(); res.encrypted_secret = secret.encrypt(PSLICE() << master_secret.as_slice() << value_hash.as_slice()).as_slice().str(); @@ -985,9 +1008,9 @@ static EncryptedSecureFile encrypt_secure_file(FileManager *file_manager, const static vector encrypt_secure_files(FileManager *file_manager, const secure_storage::Secret &master_secret, - vector files, string &to_hash) { - return transform(files, - [&](auto file_id) { return encrypt_secure_file(file_manager, master_secret, file_id, to_hash); }); + vector files, string &to_hash) { + return transform( + files, [&](auto dated_file) { return encrypt_secure_file(file_manager, master_secret, dated_file, to_hash); }); } static EncryptedSecureData encrypt_secure_data(const secure_storage::Secret &master_secret, Slice data, diff --git a/td/telegram/SecureValue.h b/td/telegram/SecureValue.h index 3459b9ae..9556c4b1 100644 --- a/td/telegram/SecureValue.h +++ b/td/telegram/SecureValue.h @@ -55,9 +55,16 @@ vector> get_passport_data_types_obj string get_secure_value_data_field_name(SecureValueType type, string field_name); -struct EncryptedSecureFile { +struct DatedFile { FileId file_id; int32 date = 0; +}; + +bool operator==(const DatedFile &lhs, const DatedFile &rhs); +bool operator!=(const DatedFile &lhs, const DatedFile &rhs); + +struct EncryptedSecureFile { + DatedFile file; string file_hash; string encrypted_secret; }; @@ -79,11 +86,6 @@ telegram_api::object_ptr get_input_secure_file_ob const EncryptedSecureFile &file, SecureInputFile &input_file); -td_api::object_ptr get_encrypted_file_object(FileManager *file_manager, const EncryptedSecureFile &file); - -vector> get_encrypted_files_object(FileManager *file_manager, - const vector &files); - vector> get_input_secure_files_object( FileManager *file_manager, const vector &file, vector &input_files); @@ -167,8 +169,8 @@ class SecureValue { public: SecureValueType type = SecureValueType::None; string data; - vector files; - FileId selfie; + vector files; + DatedFile selfie; }; struct SecureValueWithCredentials { diff --git a/td/telegram/SecureValue.hpp b/td/telegram/SecureValue.hpp index fe61b038..15b36326 100644 --- a/td/telegram/SecureValue.hpp +++ b/td/telegram/SecureValue.hpp @@ -15,17 +15,27 @@ namespace td { template -void store(EncryptedSecureFile file, StorerT &storer) { +void store(DatedFile file, StorerT &storer) { store(file.file_id, storer); store(file.date, storer); +} + +template +void parse(DatedFile &file, ParserT &parser) { + parse(file.file_id, parser); + parse(file.date, parser); +} + +template +void store(EncryptedSecureFile file, StorerT &storer) { + store(file.file, storer); store(file.file_hash, storer); store(file.encrypted_secret, storer); } template void parse(EncryptedSecureFile &file, ParserT &parser) { - parse(file.file_id, parser); - parse(file.date, parser); + parse(file.file, parser); parse(file.file_hash, parser); parse(file.encrypted_secret, parser); } @@ -62,7 +72,7 @@ template void store(const EncryptedSecureValue &value, StorerT &storer) { bool has_data_hash = !value.data.hash.empty(); bool has_files = !value.files.empty(); - bool has_selfie = value.selfie.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);