diff --git a/CMakeLists.txt b/CMakeLists.txt index a5d4de9ca..41aef850e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -401,6 +401,7 @@ set(TDLIB_SOURCE td/telegram/SecretChatDb.cpp td/telegram/SecretChatsManager.cpp td/telegram/SecureStorage.cpp + td/telegram/SecureValue.cpp td/telegram/SequenceDispatcher.cpp td/telegram/StateManager.cpp td/telegram/StickersManager.cpp @@ -521,6 +522,7 @@ set(TDLIB_SOURCE td/telegram/SecretChatsManager.h td/telegram/SecretInputMedia.h td/telegram/SecureStorage.h + td/telegram/SecureValue.h td/telegram/SequenceDispatcher.h td/telegram/StateManager.h td/telegram/StickersManager.h @@ -551,6 +553,7 @@ set(TDLIB_SOURCE td/telegram/Payments.hpp td/telegram/Photo.hpp td/telegram/ReplyMarkup.hpp + td/telegram/SecureValue.hpp td/telegram/StickersManager.hpp td/telegram/VideoNotesManager.hpp td/telegram/VideosManager.hpp diff --git a/example/ruby/Gemfile.lock b/example/ruby/Gemfile.lock index 22954eddf..4305597ab 100644 --- a/example/ruby/Gemfile.lock +++ b/example/ruby/Gemfile.lock @@ -14,4 +14,4 @@ DEPENDENCIES tdlib-ruby BUNDLED WITH - 1.16.1 + 1.16.1 diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 380f47baa..7ada26605 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -59,6 +59,9 @@ authenticationCodeTypeFlashCall pattern:string = AuthenticationCodeType; //@description Information about the authentication code that was sent @phone_number A phone number that is being authenticated @type Describes the way the code was sent to the user @next_type Describes the way the next code will be sent to the user; may be null @timeout Timeout before the code should be re-sent, in seconds authenticationCodeInfo phone_number:string type:AuthenticationCodeType next_type:AuthenticationCodeType timeout:int32 = AuthenticationCodeInfo; +//@description Information about the email address authentication code that was sent @email_address_pattern Pattern of the email address to which an authentication code was sent +emailAddressAuthenticationCodeInfo email_address_pattern:string = EmailAddressAuthenticationCodeInfo; + //@class AuthorizationState @description Represents the current authorization state of the client @@ -95,9 +98,6 @@ authorizationStateClosed = AuthorizationState; //@description Represents the current state of 2-step verification @has_password True if a 2-step verification password has been set up @password_hint Hint for the password; can be empty @has_recovery_email_address True if a recovery email has been set up @unconfirmed_recovery_email_address_pattern Pattern of the email address to which a confirmation email was sent passwordState has_password:Bool password_hint:string has_recovery_email_address:Bool unconfirmed_recovery_email_address_pattern:string = PasswordState; -//@description Contains information available to the user after requesting password recovery @recovery_email_address_pattern Pattern of the email address to which a recovery email was sent -passwordRecoveryInfo recovery_email_address_pattern:string = PasswordRecoveryInfo; - //@description Contains information about the current recovery email address @recovery_email_address Recovery email address recoveryEmailAddress recovery_email_address:string = RecoveryEmailAddress; @@ -797,6 +797,58 @@ 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; +//@class PassportDataType @description Contains type of a Telegram Passport data + +//@description The Telegram Passport data contains a user's personal details +passportDataTypePersonalDetails = PassportDataType; + +//@description The Telegram Passport data contains a user's passport +passportDataTypePassport = PassportDataType; + +//@description The Telegram Passport data contains a user's driver license +passportDataTypeDriverLicense = PassportDataType; + +//@description The Telegram Passport data contains a user's identity card +passportDataTypeIdentityCard = PassportDataType; + +//@description The Telegram Passport data contains a user's address +passportDataTypeAddress = PassportDataType; + +//@description The Telegram Passport data contains a user's utility bill +passportDataTypeUtilityBill = PassportDataType; + +//@description The Telegram Passport data contains a user's bank statement +passportDataTypeBankStatement = PassportDataType; + +//@description The Telegram Passport data contains a user's rental agreement +passportDataTypeRentalAgreement = PassportDataType; + +//@description The Telegram Passport data contains a user's phone number +passportDataTypePhoneNumber = PassportDataType; + +//@description The Telegram Passport data contains a user's email address +passportDataTypeEmailAddress = PassportDataType; + + +//@description Contains information about a Telegram Passport data @type Telegram Passport data type @data TODO data should be typed @files List of attached files +passportData type:PassportDataType data:string files:vector = PassportData; + +//@description Contains information about a Telegram Passport data to save @type Telegram Passport data type @data TODO data should be typed @files List of attached files +inputPassportData type:PassportDataType data:string files:vector = InputPassportData; + + +//@class PassportAuthorizationForm Contains information about requested Telegram Passport authorization form @data Available data +passportAuthorizationForm id:int32 data:vector = PassportAuthorizationForm; + + +//@class EncryptedCredentials Contains an encrypted Telegram Passport data credentials @data The encrypted credentials @hash The decrypted data hash @secret Encrypted by service public key secret for data decryption +encryptedCredentials data:bytes hash:bytes secret:bytes = EncryptedCredentials; + + +//@description Contains information about an encrypted Telegram Passport data @type Telegram Passport data type @data Encrypted data about the user @files List of attached files @value Unencrypted data, phone number or email address +encryptedPassportData type:PassportDataType data:bytes files:vector value:string = EncryptedPassportData; + + //@class MessageContent @description Contains the content of a message //@description A text message @text Text of the message @web_page A preview of the web page that's mentioned in the text; may be null @@ -912,6 +964,12 @@ messageContactRegistered = MessageContent; //@description The current user has connected a website by logging in using Telegram Login Widget on it @domain_name Domain name of the connected website messageWebsiteConnected domain_name:string = MessageContent; +//@description Telegram Passport data has been sent @types List of types of sent data +messagePassportDataSent types:vector = MessageContent; + +//@description Telegram Passport data has been received; for bots only @data List of received Telegram Passport data @credentials Encrypted Secure storage data credentials +messagePassportDataReceived data:vector credentials:encryptedCredentials = MessageContent; + //@description Message content that is not supported by the client messageUnsupported = MessageContent; @@ -1617,6 +1675,9 @@ fileTypeProfilePhoto = FileType; //@description The file was sent to a secret chat (the file type is not known to the server) fileTypeSecret = FileType; +fileTypeSecure = FileType; +fileTypeSecureEncrypted = FileType; + //@description The file is a sticker fileTypeSticker = FileType; @@ -2032,7 +2093,7 @@ getRecoveryEmailAddress password:string = RecoveryEmailAddress; setRecoveryEmailAddress password:string new_recovery_email_address:string = PasswordState; //@description Requests to send a password recovery code to an email address that was previously set up -requestPasswordRecovery = PasswordRecoveryInfo; +requestPasswordRecovery = EmailAddressAuthenticationCodeInfo; //@description Recovers the password using a recovery code sent to an email address that was previously set up @recovery_code Recovery code to check recoverPassword recovery_code:string = PasswordState; @@ -2814,6 +2875,44 @@ addNetworkStatistics entry:NetworkStatisticsEntry = Ok; resetNetworkStatistics = Ok; +//@description Returns filled Telegram Passport data @type Data type @password Password of the current user +getPassportData type:PassportDataType password:string = PassportData; + +//@description Sets Telegram Passport data @type Data type @password Password of the current user +setPassportData value:InputPassportData password:string = PassportData; + +//@description Deletes Telegram Passport data @type Data type +deletePassportData type:PassportDataType = Ok; + + +//@description Sends phone number verification code for Telegram Passport +//@phone_number The phone number of the user, in international format @allow_flash_call Pass true if the authentication code may be sent via flash call to the specified phone number @is_current_phone_number Pass true if the phone number is used on the current device. Ignored if allow_flash_call is false +sendPhoneNumberVerificationCode phone_number:string allow_flash_call:Bool is_current_phone_number:Bool = AuthenticationCodeInfo; + +//@description Resends phone number verification code for Telegram Passport +resendPhoneNumberVerificationCode = AuthenticationCodeInfo; + +//@description Checks phone number verification code for Telegram Passport @code The verification code +checkPhoneNumberVerificationCode code:string = Ok; + + +//@description Sends email address verification code for Telegram Passport @email_address The email address +sendEmailAddressVerificationCode email_address:string = EmailAddressAuthenticationCodeInfo; + +//@description Resends email address verification code for Telegram Passport +resendEmailAddressVerificationCode = EmailAddressAuthenticationCodeInfo; + +//@description Checks email address verification code for Telegram Passport @code The verification code +checkEmailAddressVerificationCode code:string = Ok; + + +//@description Returns Telegram Passport authorization form for sharing data with a service @bot_id Service's bot identifier @scope Telegram Passport data types requested by the service @public_key Service's public_key +getPassportAuthorizationForm bot_id:int32 scope:string public_key:string = PassportAuthorizationForm; + +//@description Sends Telegram Passport authorization form, effectively sharing data with the service @autorization_form_id Authorization form identifier +sendPassportAuthorizationForm autorization_form_id:int32 = Ok; + + //@description Informs the server about the number of pending bot updates if they haven't been processed for a long time; for bots only @pending_update_count The number of pending updates @error_message The last error message setBotUpdatesStatus pending_update_count:int32 error_message:string = Ok; diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index dd7f6d570..67145cb7c 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 11e5f7f72..7dedeed4e 100644 --- a/td/generate/scheme/telegram_api.tl +++ b/td/generate/scheme/telegram_api.tl @@ -67,6 +67,7 @@ inputPhoto#fb95c6c4 id:long access_hash:long = InputPhoto; inputFileLocation#14637196 volume_id:long local_id:int secret:long = InputFileLocation; inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; inputDocumentFileLocation#430f0724 id:long access_hash:long version:int = InputFileLocation; +inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation; inputAppEvent#770656a8 time:double type:string peer:long data:string = InputAppEvent; @@ -104,7 +105,7 @@ userStatusLastMonth#77ebc742 = UserStatus; chatEmpty#9ba2d800 id:int = Chat; chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat; chatForbidden#7328bdb id:int title:string = Chat; -channel#450b7115 flags:# creator:flags.0?true left:flags.2?true editor:flags.3?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChannelAdminRights banned_rights:flags.15?ChannelBannedRights participants_count:flags.17?int = Chat; +channel#c88974ac flags:# creator:flags.0?true left:flags.2?true editor:flags.3?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChannelAdminRights banned_rights:flags.15?ChannelBannedRights participants_count:flags.17?int = Chat; channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat; chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector = ChatFull; @@ -156,6 +157,8 @@ messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDis messageActionScreenshotTaken#4792929b = MessageAction; messageActionCustomAction#fae69f56 message:string = MessageAction; messageActionBotAllowed#abe9affe domain:string = MessageAction; +messageActionSecureValuesSentMe#1b287353 values:Vector credentials:SecureCredentialsEncrypted = MessageAction; +messageActionSecureValuesSent#d95c6154 types:Vector = MessageAction; dialog#e4def5db flags:# pinned:flags.2?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog; @@ -445,7 +448,7 @@ documentAttributeFilename#15590068 file_name:string = DocumentAttribute; documentAttributeHasStickers#9801d2f7 = DocumentAttribute; messages.stickersNotModified#f1749a22 = messages.Stickers; -messages.stickers#8a8ecd32 hash:string stickers:Vector = messages.Stickers; +messages.stickers#e4599bbd hash:int stickers:Vector = messages.Stickers; stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; @@ -468,12 +471,12 @@ authorization#7bf2e6f6 hash:long flags:int device_model:string platform:string s account.authorizations#1250abde authorizations:Vector = account.Authorizations; -account.noPassword#96dabc18 new_salt:bytes email_unconfirmed_pattern:string = account.Password; -account.password#7c18141c current_salt:bytes new_salt:bytes hint:string has_recovery:Bool email_unconfirmed_pattern:string = account.Password; +account.noPassword#5ea182f6 new_salt:bytes new_secure_salt:bytes secure_random:bytes email_unconfirmed_pattern:string = account.Password; +account.password#d06c5fc3 current_salt:bytes new_salt:bytes new_secure_salt:bytes secure_random:bytes hint:string has_recovery:Bool email_unconfirmed_pattern:string = account.Password; -account.passwordSettings#b7b72ab3 email:string = account.PasswordSettings; +account.passwordSettings#7bd9c3f1 email:string secure_salt:bytes secure_secret:bytes secure_secret_id:long = account.PasswordSettings; -account.passwordInputSettings#86916deb flags:# new_salt:flags.0?bytes new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string = account.PasswordInputSettings; +account.passwordInputSettings#21ffa60d flags:# new_salt:flags.0?bytes new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_salt:flags.2?bytes new_secure_secret:flags.2?bytes new_secure_secret_id:flags.2?long = account.PasswordInputSettings; auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; @@ -839,6 +842,40 @@ messages.foundStickerSets#5108d648 hash:int sets:Vector = mes fileHash#6242c773 offset:int limit:int hash:bytes = FileHash; +inputSecureFileUploaded#3334b0f0 id:long parts:int md5_checksum:string file_hash:bytes secret:bytes = InputSecureFile; +inputSecureFile#5367e5be id:long access_hash:long = InputSecureFile; + +secureFileEmpty#64199744 = SecureFile; +secureFile#e0277a62 id:long access_hash:long size:int dc_id:int date:int file_hash:bytes secret:bytes = SecureFile; + +secureData#8aeabec3 data:bytes data_hash:bytes secret:bytes = SecureData; + +securePlainPhone#7d6099dd phone:string = SecurePlainData; +securePlainEmail#21ec5a5f email:string = SecurePlainData; + +secureValueTypePersonalDetails#9d2a81e3 = SecureValueType; +secureValueTypePassport#3dac6a00 = SecureValueType; +secureValueTypeDriverLicense#6e425c4 = SecureValueType; +secureValueTypeIdentityCard#a0d0744b = SecureValueType; +secureValueTypeAddress#cbe31e26 = SecureValueType; +secureValueTypeUtilityBill#fc36954e = SecureValueType; +secureValueTypeBankStatement#89137c0d = SecureValueType; +secureValueTypeRentalAgreement#8b883488 = 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; + +inputSecureValue#c0da30f0 flags:# type:SecureValueType data:flags.0?SecureData files:flags.1?Vector plain_data:flags.2?SecurePlainData selfie:flags.3?InputSecureFile = InputSecureValue; + +secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash; + +secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted; + +account.authorizationForm#b9d3d1f0 flags:# selfie_required:flags.1?true required_types:Vector values:Vector users:Vector privacy_policy_url:flags.0?string = account.AuthorizationForm; + +account.sentEmailCode#28b1633b email_pattern:string = account.SentEmailCode; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -895,6 +932,15 @@ account.getTmpPassword#4a82327e password_hash:bytes period:int = account.TmpPass account.getWebAuthorizations#182e6d6f = account.WebAuthorizations; account.resetWebAuthorization#2d01b9ef hash:long = Bool; account.resetWebAuthorizations#682d2594 = Bool; +account.getSecureValue#73665bc2 types:Vector = Vector; +account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long = SecureValue; +account.deleteSecureValue#b880bc4b types:Vector = Bool; +account.getAuthorizationForm#b86ba8e1 bot_id:int scope:string public_key:string = account.AuthorizationForm; +account.acceptAuthorization#e7027c94 bot_id:int scope:string public_key:string value_hashes:Vector credentials:SecureCredentialsEncrypted = Bool; +account.sendVerifyPhoneCode#823380b4 flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode; +account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool; +account.sendVerifyEmailCode#7011509f email:string = account.SentEmailCode; +account.verifyEmail#ecba39db email:string code:string = Bool; users.getUsers#d91a548 id:Vector = Vector; users.getFullUser#ca30a5b1 id:InputUser = UserFull; @@ -950,7 +996,7 @@ messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long da messages.receivedQueue#55a5bb66 max_qts:int = Vector; messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; -messages.getStickers#85cb5182 flags:# exclude_featured:flags.0?true emoticon:string hash:string = messages.Stickers; +messages.getStickers#43d4f2c emoticon:string hash:int = messages.Stickers; messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers; messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector = MessageMedia; messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite; diff --git a/td/generate/scheme/telegram_api.tlo b/td/generate/scheme/telegram_api.tlo index 6557f4c0f..deb283d21 100644 Binary files a/td/generate/scheme/telegram_api.tlo and b/td/generate/scheme/telegram_api.tlo differ diff --git a/td/telegram/AnimationsManager.cpp b/td/telegram/AnimationsManager.cpp index 6a372b1fc..5c8c1a24c 100644 --- a/td/telegram/AnimationsManager.cpp +++ b/td/telegram/AnimationsManager.cpp @@ -517,8 +517,7 @@ int32 AnimationsManager::get_saved_animations_hash() const { CHECK(animation != nullptr); auto file_view = td_->file_manager_->get_file_view(animation_id); CHECK(file_view.has_remote_location()); - CHECK(!file_view.remote_location().is_encrypted()); - CHECK(!file_view.remote_location().is_web()); + CHECK(file_view.remote_location().is_document()); auto id = static_cast(file_view.remote_location().get_id()); numbers.push_back(static_cast(id >> 32)); numbers.push_back(static_cast(id & 0xFFFFFFFF)); @@ -598,14 +597,14 @@ bool AnimationsManager::add_saved_animation_impl(FileId animation_id, Promisefile_manager_->get_file_view(file_id); CHECK(file_view.has_remote_location()); - CHECK(!file_view.remote_location().is_encrypted()); + CHECK(file_view.remote_location().is_document()); CHECK(!file_view.remote_location().is_web()); td_->create_handler(std::move(promise))->send(file_view.remote_location().as_input_document(), true); diff --git a/td/telegram/AuthManager.cpp b/td/telegram/AuthManager.cpp index 338148373..2c3e43e64 100644 --- a/td/telegram/AuthManager.cpp +++ b/td/telegram/AuthManager.cpp @@ -25,6 +25,7 @@ #include "td/utils/buffer.h" #include "td/utils/crypto.h" +#include "td/utils/format.h" #include "td/utils/logging.h" #include "td/utils/ScopeGuard.h" #include "td/utils/Time.h" diff --git a/td/telegram/AuthManager.h b/td/telegram/AuthManager.h index d5e9cbf3d..21a020e34 100644 --- a/td/telegram/AuthManager.h +++ b/td/telegram/AuthManager.h @@ -15,6 +15,7 @@ #include "td/utils/common.h" #include "td/utils/Slice.h" #include "td/utils/Status.h" +#include "td/utils/Time.h" namespace td { class SendCodeHelper { diff --git a/td/telegram/AuthManager.hpp b/td/telegram/AuthManager.hpp index 89027abd6..6d4424e17 100644 --- a/td/telegram/AuthManager.hpp +++ b/td/telegram/AuthManager.hpp @@ -6,6 +6,8 @@ // #include "td/telegram/AuthManager.h" +#include "td/utils/format.h" +#include "td/utils/logging.h" #include "td/utils/tl_helpers.h" namespace td { diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 72c5636a9..689016a11 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -2310,6 +2310,9 @@ class ContactsManager::UploadProfilePhotoCallback : public FileManager::UploadCa void on_upload_encrypted_ok(FileId file_id, tl_object_ptr input_file) override { UNREACHABLE(); } + void on_upload_secure_ok(FileId file_id, tl_object_ptr input_file) override { + UNREACHABLE(); + } void on_upload_error(FileId file_id, Status error) override { send_closure_later(G()->contacts_manager(), &ContactsManager::on_upload_profile_photo_error, file_id, std::move(error)); @@ -5284,7 +5287,7 @@ ContactsManager::User *ContactsManager::get_user_force(UserId user_id) { auto user = telegram_api::make_object( flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, - false /*ignored*/, 777000, 1, "Telegram", string(), string(), "42777", std::move(profile_photo), nullptr, 0, + false /*ignored*/, 777000, 1, "Telegram", "Updates", string(), "42777", std::move(profile_photo), nullptr, 0, string(), string(), string()); on_get_user(std::move(user)); u = get_user(user_id); diff --git a/td/telegram/Global.h b/td/telegram/Global.h index 63c07d5c3..c11f101c9 100644 --- a/td/telegram/Global.h +++ b/td/telegram/Global.h @@ -43,6 +43,7 @@ class FileManager; class MtprotoHeader; class MessagesManager; class NetQueryDispatcher; +class PasswordManager; class SecretChatsManager; class StateManager; class StickersManager; @@ -158,6 +159,12 @@ class Global : public ActorContext { void set_messages_manager(ActorId messages_manager) { messages_manager_ = messages_manager; } + ActorId password_manager() const { + return password_manager_; + } + void set_password_manager(ActorId password_manager) { + password_manager_ = password_manager; + } ActorId secret_chats_manager() const { return secret_chats_manager_; } @@ -291,6 +298,7 @@ class Global : public ActorContext { ActorId contacts_manager_; ActorId file_manager_; ActorId messages_manager_; + ActorId password_manager_; ActorId secret_chats_manager_; ActorId call_manager_; ActorId stickers_manager_; diff --git a/td/telegram/InlineQueriesManager.cpp b/td/telegram/InlineQueriesManager.cpp index e7ae7a036..abf6240d4 100644 --- a/td/telegram/InlineQueriesManager.cpp +++ b/td/telegram/InlineQueriesManager.cpp @@ -5,6 +5,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #include "td/telegram/InlineQueriesManager.h" + #include "td/telegram/td_api.h" #include "td/telegram/td_api.hpp" #include "td/telegram/telegram_api.h" diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 653b8832e..815b64880 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -42,6 +42,7 @@ #include "td/telegram/ReplyMarkup.hpp" #include "td/telegram/SecretChatActor.h" #include "td/telegram/SecretChatsManager.h" +#include "td/telegram/SecureValue.hpp" #include "td/telegram/SequenceDispatcher.h" #include "td/telegram/StickersManager.h" #include "td/telegram/StickersManager.hpp" @@ -3327,6 +3328,9 @@ class MessagesManager::UploadMediaCallback : public FileManager::UploadCallback send_closure_later(G()->messages_manager(), &MessagesManager::on_upload_media, file_id, nullptr, std::move(input_file)); } + void on_upload_secure_ok(FileId file_id, tl_object_ptr input_file) override { + UNREACHABLE(); + } void on_upload_error(FileId file_id, Status error) override { send_closure_later(G()->messages_manager(), &MessagesManager::on_upload_media_error, file_id, std::move(error)); } @@ -3340,6 +3344,9 @@ class MessagesManager::UploadThumbnailCallback : public FileManager::UploadCallb void on_upload_encrypted_ok(FileId file_id, tl_object_ptr input_file) override { UNREACHABLE(); } + void on_upload_secure_ok(FileId file_id, tl_object_ptr input_file) override { + UNREACHABLE(); + } void on_upload_error(FileId file_id, Status error) override { send_closure_later(G()->messages_manager(), &MessagesManager::on_upload_thumbnail, file_id, nullptr); } @@ -3354,6 +3361,9 @@ class MessagesManager::UploadDialogPhotoCallback : public FileManager::UploadCal void on_upload_encrypted_ok(FileId file_id, tl_object_ptr input_file) override { UNREACHABLE(); } + void on_upload_secure_ok(FileId file_id, tl_object_ptr input_file) override { + UNREACHABLE(); + } void on_upload_error(FileId file_id, Status error) override { send_closure_later(G()->messages_manager(), &MessagesManager::on_upload_dialog_photo_error, file_id, std::move(error)); @@ -3595,6 +3605,17 @@ static void store(const MessageContent *content, StorerT &storer) { store(m->domain_name, storer); break; } + case MessagePassportDataSent::ID: { + auto m = static_cast(content); + store(m->types, storer); + break; + } + case MessagePassportDataReceived::ID: { + auto m = static_cast(content); + store(m->values, storer); + store(m->credentials, storer); + break; + } default: UNREACHABLE(); } @@ -3901,6 +3922,19 @@ static void parse(unique_ptr &content, ParserT &parser) { content = std::move(m); break; } + case MessagePassportDataSent::ID: { + auto m = make_unique(); + parse(m->types, parser); + content = std::move(m); + break; + } + case MessagePassportDataReceived::ID: { + auto m = make_unique(); + parse(m->values, parser); + parse(m->credentials, parser); + content = std::move(m); + break; + } default: UNREACHABLE(); } @@ -4834,6 +4868,8 @@ int32 MessagesManager::get_message_content_index_mask(const MessageContent *cont case MessageExpiredVideo::ID: case MessageCustomServiceAction::ID: case MessageWebsiteConnected::ID: + case MessagePassportDataSent::ID: + case MessagePassportDataReceived::ID: return 0; default: UNREACHABLE(); @@ -5688,6 +5724,8 @@ bool MessagesManager::need_cancel_user_dialog_action(int32 action_id, int32 mess case MessageContactRegistered::ID: case MessageCustomServiceAction::ID: case MessageWebsiteConnected::ID: + case MessagePassportDataSent::ID: + case MessagePassportDataReceived::ID: return false; default: UNREACHABLE(); @@ -7351,6 +7389,8 @@ bool MessagesManager::is_secret_message_content(int32 ttl, int32 content_type) { case MessageContactRegistered::ID: case MessageCustomServiceAction::ID: case MessageWebsiteConnected::ID: + case MessagePassportDataSent::ID: + case MessagePassportDataReceived::ID: return false; default: UNREACHABLE(); @@ -7399,6 +7439,8 @@ bool MessagesManager::is_service_message_content(int32 content_type) { case MessageContactRegistered::ID: case MessageCustomServiceAction::ID: case MessageWebsiteConnected::ID: + case MessagePassportDataSent::ID: + case MessagePassportDataReceived::ID: return true; default: UNREACHABLE(); @@ -7447,6 +7489,8 @@ bool MessagesManager::can_have_message_content_caption(int32 content_type) { case MessageExpiredVideo::ID: case MessageCustomServiceAction::ID: case MessageWebsiteConnected::ID: + case MessagePassportDataSent::ID: + case MessagePassportDataReceived::ID: return false; default: UNREACHABLE(); @@ -7520,6 +7564,8 @@ string MessagesManager::get_search_text(const Message *m) { case MessageExpiredVideo::ID: case MessageCustomServiceAction::ID: case MessageWebsiteConnected::ID: + case MessagePassportDataSent::ID: + case MessagePassportDataReceived::ID: return ""; default: UNREACHABLE(); @@ -7568,6 +7614,8 @@ bool MessagesManager::is_allowed_media_group_content(int32 content_type) { case MessageContactRegistered::ID: case MessageCustomServiceAction::ID: case MessageWebsiteConnected::ID: + case MessagePassportDataSent::ID: + case MessagePassportDataReceived::ID: return false; default: UNREACHABLE(); @@ -8897,6 +8945,16 @@ tl_object_ptr MessagesManager::get_message_content_objec const MessageWebsiteConnected *m = static_cast(content); return make_tl_object(m->domain_name); } + case MessagePassportDataSent::ID: { + const MessagePassportDataSent *m = static_cast(content); + return make_tl_object(get_passport_data_types_object(m->types)); + } + case MessagePassportDataReceived::ID: { + const MessagePassportDataReceived *m = static_cast(content); + return make_tl_object( + get_encrypted_passport_data_object(td_->file_manager_.get(), m->values), + get_encrypted_credentials_object(m->credentials)); + } default: UNREACHABLE(); return nullptr; @@ -14497,6 +14555,8 @@ SecretInputMedia MessagesManager::get_secret_input_media(const MessageContent *c case MessageExpiredVideo::ID: case MessageCustomServiceAction::ID: case MessageWebsiteConnected::ID: + case MessagePassportDataSent::ID: + case MessagePassportDataReceived::ID: break; default: UNREACHABLE(); @@ -14668,6 +14728,8 @@ tl_object_ptr MessagesManager::get_input_media( case MessageExpiredVideo::ID: case MessageCustomServiceAction::ID: case MessageWebsiteConnected::ID: + case MessagePassportDataSent::ID: + case MessagePassportDataReceived::ID: break; default: UNREACHABLE(); @@ -14736,6 +14798,8 @@ void MessagesManager::delete_message_content_thumbnail(MessageContent *content) case MessageExpiredVideo::ID: case MessageCustomServiceAction::ID: case MessageWebsiteConnected::ID: + case MessagePassportDataSent::ID: + case MessagePassportDataReceived::ID: break; default: UNREACHABLE(); @@ -15023,6 +15087,8 @@ Status MessagesManager::can_send_message_content(DialogId dialog_id, const Messa case MessageExpiredVideo::ID: case MessageCustomServiceAction::ID: case MessageWebsiteConnected::ID: + case MessagePassportDataSent::ID: + case MessagePassportDataReceived::ID: UNREACHABLE(); } return Status::OK(); @@ -15452,6 +15518,10 @@ void MessagesManager::add_message_dependencies(Dependencies &dependencies, Dialo break; case MessageWebsiteConnected::ID: break; + case MessagePassportDataSent::ID: + break; + case MessagePassportDataReceived::ID: + break; default: UNREACHABLE(); break; @@ -16144,7 +16214,7 @@ void MessagesManager::do_send_message(DialogId dialog_id, Message *m, vectorcontacts_manager_->get_secret_chat_layer(dialog_id.get_secret_chat_id()); auto secret_input_media = get_secret_input_media(content, nullptr, BufferSlice(), layer); if (secret_input_media.empty()) { - CHECK(file_view.is_encrypted()); + CHECK(file_view.is_encrypted_secret()); CHECK(file_id.is_valid()); being_uploaded_files_[file_id] = {FullMessageId(dialog_id, m->message_id), thumbnail_file_id}; LOG(INFO) << "Ask to upload encrypted file " << file_id; @@ -16947,6 +17017,8 @@ bool MessagesManager::can_edit_message(DialogId dialog_id, const Message *m, boo case MessageExpiredVideo::ID: case MessageCustomServiceAction::ID: case MessageWebsiteConnected::ID: + case MessagePassportDataSent::ID: + case MessagePassportDataReceived::ID: return false; default: UNREACHABLE(); @@ -18730,6 +18802,8 @@ FullMessageId MessagesManager::on_send_message_success(int64 random_id, MessageI case MessageExpiredVideo::ID: case MessageCustomServiceAction::ID: case MessageWebsiteConnected::ID: + case MessagePassportDataSent::ID: + case MessagePassportDataReceived::ID: LOG(ERROR) << "Receive new file " << new_file_id << " in a sent message of the type " << content_type; break; default: @@ -21124,7 +21198,7 @@ unique_ptr MessagesManager::dup_message_content(DialogId dialog_ bool to_secret = dialog_id.get_type() == DialogType::SecretChat; auto fix_file_id = [dialog_id, to_secret, file_manager = td_->file_manager_.get()](FileId file_id) { auto file_view = file_manager->get_file_view(file_id); - if (to_secret && !file_view.is_encrypted()) { + if (to_secret && !file_view.is_encrypted_secret()) { auto download_file_id = file_manager->dup_file_id(file_id); file_id = file_manager ->register_generate(FileType::Encrypted, FileLocationSource::FromServer, "", @@ -21302,6 +21376,8 @@ unique_ptr MessagesManager::dup_message_content(DialogId dialog_ case MessageExpiredVideo::ID: case MessageCustomServiceAction::ID: case MessageWebsiteConnected::ID: + case MessagePassportDataSent::ID: + case MessagePassportDataReceived::ID: return nullptr; default: UNREACHABLE(); @@ -21468,6 +21544,18 @@ unique_ptr MessagesManager::get_message_action_content( auto bot_allowed = move_tl_object_as(action); return make_unique(std::move(bot_allowed->domain_)); } + case telegram_api::messageActionSecureValuesSent::ID: { + LOG_IF(ERROR, td_->auth_manager_->is_bot()) << "Receive MessageActionSecureValuesSent"; + auto secure_values = move_tl_object_as(action); + return make_unique(get_secure_value_types(std::move(secure_values->types_))); + } + case telegram_api::messageActionSecureValuesSentMe::ID: { + LOG_IF(ERROR, !td_->auth_manager_->is_bot()) << "Receive MessageActionSecureValuesSentMe"; + auto secure_values = move_tl_object_as(action); + return make_unique( + get_encrypted_secure_values(td_->file_manager_.get(), std::move(secure_values->values_)), + get_secure_credentials(std::move(secure_values->credentials_))); + } default: UNREACHABLE(); } @@ -22985,6 +23073,26 @@ bool MessagesManager::update_message_content(DialogId dialog_id, Message *old_me } break; } + case MessagePassportDataSent::ID: { + auto old_ = static_cast(old_content.get()); + auto new_ = static_cast(new_content.get()); + if (old_->types != new_->types) { + need_update = true; + } + break; + } + case MessagePassportDataReceived::ID: { + auto old_ = static_cast(old_content.get()); + auto new_ = static_cast(new_content.get()); + if (old_->values != new_->values) { + // FIXME merge files? + need_update = true; + } + if (old_->credentials != new_->credentials) { + need_update = true; + } + break; + } case MessageUnsupported::ID: break; default: diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 7ecdea98e..619b2ea35 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -38,6 +38,7 @@ #include "td/telegram/ReplyMarkup.h" #include "td/telegram/SecretChatId.h" #include "td/telegram/SecretInputMedia.h" +#include "td/telegram/SecureValue.h" #include "td/telegram/UserId.h" #include "td/telegram/WebPageId.h" @@ -626,6 +627,36 @@ class MessageWebsiteConnected : public MessageContent { } }; +class MessagePassportDataSent : public MessageContent { + public: + vector types; + + MessagePassportDataSent() = default; + explicit MessagePassportDataSent(vector &&types) : types(std::move(types)) { + } + + static const int32 ID = 38; + int32 get_id() const override { + return ID; + } +}; + +class MessagePassportDataReceived : public MessageContent { + public: + vector values; + SecureCredentials credentials; + + MessagePassportDataReceived() = default; + MessagePassportDataReceived(vector &&values, SecureCredentials &&credentials) + : values(std::move(values)), credentials(std::move(credentials)) { + } + + static const int32 ID = 39; + int32 get_id() const override { + return ID; + } +}; + class InputMessageText { public: FormattedText text; diff --git a/td/telegram/PasswordManager.cpp b/td/telegram/PasswordManager.cpp index 7fbff2ba0..0a0a1e3fb 100644 --- a/td/telegram/PasswordManager.cpp +++ b/td/telegram/PasswordManager.cpp @@ -14,6 +14,7 @@ #include "td/utils/crypto.h" #include "td/utils/logging.h" #include "td/utils/Random.h" +#include "td/utils/Slice.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" // TODO: this file is already included. Why? @@ -44,6 +45,7 @@ void PasswordManager::set_password(string current_password, string new_password, update_settings.current_password = std::move(current_password); update_settings.update_password = true; + //update_settings.update_secure_secret = true; update_settings.new_password = std::move(new_password); update_settings.new_hint = std::move(new_hint); @@ -64,6 +66,52 @@ void PasswordManager::set_recovery_email_address(string password, string new_rec update_password_settings(std::move(update_settings), std::move(promise)); } +void PasswordManager::get_secure_secret(string password, optional hash, + Promise promise) { + return do_get_secure_secret(true, std::move(password), std::move(hash), std::move(promise)); +} + +void PasswordManager::do_get_secure_secret(bool recursive, string password, optional hash, + Promise promise) { + if (secret_ && (!hash || secret_.value().get_hash() == hash.value())) { + return promise.set_value(secret_.value().clone()); + } + get_full_state( + password, PromiseCreator::lambda([password, recursive, hash = std::move(hash), promise = std::move(promise), + actor_id = actor_id(this)](Result r_state) mutable { + if (r_state.is_error()) { + return promise.set_error(r_state.move_as_error()); + } + auto state = r_state.move_as_ok(); + if (!state.state.has_password) { + return promise.set_error(Status::Error(400, "2fa is off")); + } + if (state.private_state.secret) { + send_closure(actor_id, &PasswordManager::cache_secret, state.private_state.secret.value().clone()); + return promise.set_value(std::move(state.private_state.secret.value())); + } + if (!recursive) { + return promise.set_error(Status::Error(400, "Failed to get secure secret")); + } + + auto new_promise = + PromiseCreator::lambda([recursive, password, hash = std::move(hash), promise = std::move(promise), + actor_id = actor_id](Result r_ok) mutable { + if (r_ok.is_error()) { + return promise.set_error(r_ok.move_as_error()); + } + send_closure(actor_id, &PasswordManager::do_get_secure_secret, false, std::move(password), + std::move(hash), std::move(promise)); + }); + + UpdateSettings update_settings; + update_settings.current_password = password; + update_settings.update_secure_secret = true; + send_closure(actor_id, &PasswordManager::do_update_password_settings, std::move(update_settings), + std::move(state), std::move(new_promise)); + })); +} + void PasswordManager::get_temp_password_state(Promise promise) /*const*/ { promise.set_value(temp_password_state_.as_td_api()); } @@ -135,33 +183,74 @@ void PasswordManager::on_finish_create_temp_password(Result r create_temp_password_promise_.set_value(temp_password_state_.as_td_api()); } -void PasswordManager::get_recovery_email_address(string password, - Promise> promise) { +void PasswordManager::get_full_state(string password, Promise promise) { do_get_state(PromiseCreator::lambda([password = std::move(password), promise = std::move(promise), actor_id = actor_id(this)](Result r_state) mutable { if (r_state.is_error()) { return promise.set_error(r_state.move_as_error()); } - send_closure(actor_id, &PasswordManager::do_get_recovery_email_address, std::move(password), r_state.move_as_ok(), + send_closure(actor_id, &PasswordManager::do_get_full_state, std::move(password), r_state.move_as_ok(), std::move(promise)); })); } -void PasswordManager::request_password_recovery(Promise> promise) { - send_with_promise(G()->net_query_creator().create(create_storer(telegram_api::auth_requestPasswordRecovery())), - PromiseCreator::lambda([promise = std::move(promise)](Result r_query) mutable { - if (r_query.is_error()) { - return promise.set_error(r_query.move_as_error()); - } - auto r_result = fetch_result(r_query.move_as_ok()); - if (r_result.is_error()) { - return promise.set_error(r_result.move_as_error()); - } - auto result = r_result.move_as_ok(); - return promise.set_value(make_tl_object(result->email_pattern_)); +void PasswordManager::do_get_full_state(string password, PasswordState state, Promise promise) { + auto current_salt = state.current_salt; + send_with_promise(G()->net_query_creator().create(create_storer( + telegram_api::account_getPasswordSettings(calc_password_hash(password, current_salt)))), + PromiseCreator::lambda([promise = std::move(promise), state = std::move(state), + password](Result r_query) mutable { + promise.set_result([&]() -> Result { + TRY_RESULT(query, std::move(r_query)); + TRY_RESULT(result, fetch_result(std::move(query))); + PasswordPrivateState private_state; + private_state.email = result->email_; + + namespace ss = secure_storage; + auto r_secret = [&]() -> Result { + TRY_RESULT(encrypted_secret, ss::EncryptedSecret::create(result->secure_secret_.as_slice())); + return encrypted_secret.decrypt(PSLICE() << result->secure_salt_.as_slice() << password + << result->secure_salt_.as_slice()); + }(); + + LOG_IF(ERROR, r_secret.is_error()) << r_secret.error(); + LOG_IF(ERROR, r_secret.is_ok()) << "HAS SECRET"; + private_state.secret = std::move(r_secret); + return PasswordFullState{std::move(state), std::move(private_state)}; + }()); })); } +void PasswordManager::get_recovery_email_address(string password, + Promise> promise) { + get_full_state( + password, + PromiseCreator::lambda([password, promise = std::move(promise)](Result r_state) mutable { + if (r_state.is_error()) { + return promise.set_error(r_state.move_as_error()); + } + auto state = r_state.move_as_ok(); + return promise.set_value(make_tl_object(state.private_state.email)); + })); +} + +void PasswordManager::request_password_recovery( + Promise> promise) { + send_with_promise( + G()->net_query_creator().create(create_storer(telegram_api::auth_requestPasswordRecovery())), + PromiseCreator::lambda([promise = std::move(promise)](Result r_query) mutable { + if (r_query.is_error()) { + return promise.set_error(r_query.move_as_error()); + } + auto r_result = fetch_result(r_query.move_as_ok()); + if (r_result.is_error()) { + return promise.set_error(r_result.move_as_error()); + } + auto result = r_result.move_as_ok(); + return promise.set_value(make_tl_object(result->email_pattern_)); + })); +} + void PasswordManager::recover_password(string code, Promise promise) { send_with_promise(G()->net_query_creator().create(create_storer(telegram_api::auth_recoverPassword(std::move(code)))), PromiseCreator::lambda( @@ -177,23 +266,6 @@ void PasswordManager::recover_password(string code, Promise promise) { })); } -void PasswordManager::do_get_recovery_email_address(string password, PasswordState state, - Promise> promise) { - send_with_promise(G()->net_query_creator().create(create_storer( - telegram_api::account_getPasswordSettings(calc_password_hash(password, state.current_salt)))), - PromiseCreator::lambda([promise = std::move(promise)](Result r_query) mutable { - if (r_query.is_error()) { - return promise.set_error(r_query.move_as_error()); - } - auto r_result = fetch_result(r_query.move_as_ok()); - if (r_result.is_error()) { - return promise.set_error(r_result.move_as_error()); - } - auto result = r_result.move_as_ok(); - return promise.set_value(make_tl_object(result->email_)); - })); -} - void PasswordManager::update_password_settings(UpdateSettings update_settings, Promise promise) { auto result_promise = PromiseCreator::lambda( [actor_id = actor_id(this), promise = std::move(promise)](Result r_update_settings) mutable { @@ -208,9 +280,11 @@ void PasswordManager::update_password_settings(UpdateSettings update_settings, P send_closure(actor_id, &PasswordManager::get_state, std::move(promise)); }); - do_get_state( + auto password = update_settings.current_password; + get_full_state( + std::move(password), PromiseCreator::lambda([=, actor_id = actor_id(this), result_promise = std::move(result_promise), - update_settings = std::move(update_settings)](Result r_state) mutable { + update_settings = std::move(update_settings)](Result r_state) mutable { if (r_state.is_error()) { result_promise.set_error(r_state.move_as_error()); return; @@ -220,24 +294,60 @@ void PasswordManager::update_password_settings(UpdateSettings update_settings, P })); } -void PasswordManager::do_update_password_settings(UpdateSettings update_settings, PasswordState state, +namespace { +BufferSlice create_salt(Slice server_salt) { + BufferSlice new_salt(server_salt.size() + 32); + new_salt.as_slice().copy_from(server_salt); + Random::secure_bytes(new_salt.as_slice().remove_prefix(server_salt.size())); + return new_salt; +} +} // namespace +void PasswordManager::do_update_password_settings(UpdateSettings update_settings, PasswordFullState full_state, Promise promise) { + auto state = std::move(full_state.state); + auto private_state = std::move(full_state.private_state); auto new_settings = make_tl_object(); if (update_settings.update_password) { new_settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_PASSWORD_HASH_MASK; new_settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_SALT_MASK; new_settings->flags_ |= telegram_api::account_passwordInputSettings::HINT_MASK; if (!update_settings.new_password.empty()) { - BufferSlice new_salt(state.new_salt.size() * 2); - new_salt.as_slice().copy_from(state.new_salt); - Random::secure_bytes(new_salt.as_slice().remove_prefix(state.new_salt.size())); + auto new_salt = create_salt(state.new_salt); new_settings->new_salt_ = std::move(new_salt); new_settings->new_password_hash_ = calc_password_hash(update_settings.new_password, new_settings->new_salt_.as_slice().str()); new_settings->hint_ = std::move(update_settings.new_hint); + if (private_state.secret) { + update_settings.update_secure_secret = true; + } } } + + if (!state.has_password || (update_settings.update_password && update_settings.new_password.empty())) { + update_settings.update_secure_secret = false; + } + + if (update_settings.update_secure_secret) { + new_settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_SECURE_SECRET_ID_MASK; + new_settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_SECURE_SALT_MASK; + new_settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_SECURE_SECRET_MASK; + auto secret = [&]() { + if (private_state.secret) { + return std::move(private_state.secret.value()); + } + return secure_storage::Secret::create_new(); + }(); + auto new_secure_salt = create_salt(state.new_secure_salt); + auto encrypted_secret = secret.encrypt( + PSLICE() << new_secure_salt.as_slice() + << (update_settings.update_password ? update_settings.new_password : update_settings.current_password) + << new_secure_salt.as_slice()); + + new_settings->new_secure_salt_ = std::move(new_secure_salt); + new_settings->new_secure_secret_ = BufferSlice(encrypted_secret.as_slice()); + new_settings->new_secure_secret_id_ = secret.get_hash(); + } if (update_settings.update_recovery_email_address) { new_settings->flags_ |= telegram_api::account_passwordInputSettings::EMAIL_MASK; new_settings->email_ = std::move(update_settings.recovery_email_address); @@ -297,6 +407,8 @@ void PasswordManager::do_get_state(Promise promise) { state.password_hint = ""; state.current_salt = ""; state.new_salt = no_password->new_salt_.as_slice().str(); + state.new_secure_salt = no_password->new_secure_salt_.as_slice().str(); + state.secure_random = no_password->secure_random_.as_slice().str(); state.has_recovery_email_address = false; state.unconfirmed_recovery_email_address_pattern = no_password->email_unconfirmed_pattern_; } else if (result->get_id() == telegram_api::account_password::ID) { @@ -305,6 +417,8 @@ void PasswordManager::do_get_state(Promise promise) { state.password_hint = password->hint_; state.current_salt = password->current_salt_.as_slice().str(); state.new_salt = password->new_salt_.as_slice().str(); + state.new_secure_salt = password->new_secure_salt_.as_slice().str(); + state.secure_random = password->secure_random_.as_slice().str(); state.has_recovery_email_address = password->has_recovery_; state.unconfirmed_recovery_email_address_pattern = password->email_unconfirmed_pattern_; } else { @@ -313,6 +427,10 @@ void PasswordManager::do_get_state(Promise promise) { promise.set_value(std::move(state)); })); } +void PasswordManager::cache_secret(secure_storage::Secret secret) { + LOG(ERROR) << "CACHE"; + secret_ = std::move(secret); +} void PasswordManager::on_result(NetQueryPtr query) { auto token = get_link_token(); diff --git a/td/telegram/PasswordManager.h b/td/telegram/PasswordManager.h index fb67d46f6..d1bc01083 100644 --- a/td/telegram/PasswordManager.h +++ b/td/telegram/PasswordManager.h @@ -7,9 +7,11 @@ #pragma once #include "td/telegram/net/NetQuery.h" +#include "td/telegram/SecureStorage.h" #include "td/utils/Container.h" #include "td/utils/logging.h" +#include "td/utils/optional.h" #include "td/utils/Status.h" #include "td/utils/tl_helpers.h" @@ -54,9 +56,11 @@ class PasswordManager : public NetQueryCallback { void set_recovery_email_address(string password, string new_recovery_email_address, Promise promise); void get_recovery_email_address(string password, Promise> promise); - void request_password_recovery(Promise> promise); + void request_password_recovery(Promise> promise); void recover_password(string code, Promise promise); + void get_secure_secret(string password, optional hash, Promise promise); + void get_temp_password_state(Promise promise) /*const*/; void create_temp_password(string password, int32 timeout, Promise promise); void drop_temp_password(); @@ -75,12 +79,25 @@ class PasswordManager : public NetQueryCallback { string current_salt; string new_salt; + string new_secure_salt; + string secure_random; + State as_td_api() const { return td_api::make_object(has_password, password_hint, has_recovery_email_address, unconfirmed_recovery_email_address_pattern); } }; + struct PasswordPrivateState { + string email; + optional secret; + }; + + struct PasswordFullState { + PasswordState state; + PasswordPrivateState private_state; + }; + struct UpdateSettings { string current_password; @@ -88,18 +105,23 @@ class PasswordManager : public NetQueryCallback { string new_password; string new_hint; + bool update_secure_secret = false; + bool update_recovery_email_address = false; string recovery_email_address; }; + optional secret_; TempPasswordState temp_password_state_; Promise create_temp_password_promise_; void update_password_settings(UpdateSettings update_settings, Promise promise); - void do_update_password_settings(UpdateSettings update_settings, PasswordState state, Promise promise); + void do_update_password_settings(UpdateSettings update_settings, PasswordFullState full_state, Promise promise); void do_get_state(Promise promise); - void do_get_recovery_email_address(string password, PasswordState state, - Promise> promise); + void get_full_state(string password, Promise promise); + void do_get_secure_secret(bool recursive, string passwod, optional, Promise promise); + void do_get_full_state(string password, PasswordState state, Promise promise); + void cache_secret(secure_storage::Secret secret); void do_create_temp_password(string password, int32 timeout, PasswordState &&password_state, Promise promise); diff --git a/td/telegram/Photo.cpp b/td/telegram/Photo.cpp index 045ffd1e9..099603c0a 100644 --- a/td/telegram/Photo.cpp +++ b/td/telegram/Photo.cpp @@ -503,7 +503,7 @@ bool photo_has_input_media(FileManager *file_manager, const Photo &photo, bool i auto file_id = photo.photos.back().file_id; auto file_view = file_manager->get_file_view(file_id); if (is_secret) { - if (file_view.encryption_key().empty() || !file_view.has_remote_location()) { + if (!file_view.is_encrypted_secret() || !file_view.has_remote_location()) { return false; } diff --git a/td/telegram/SecureStorage.cpp b/td/telegram/SecureStorage.cpp index 1e9b890bf..c0fd4579d 100644 --- a/td/telegram/SecureStorage.cpp +++ b/td/telegram/SecureStorage.cpp @@ -5,10 +5,24 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #include "td/telegram/SecureStorage.h" + +#include "td/utils/logging.h" #include "td/utils/misc.h" +#include "td/utils/Random.h" + namespace td { namespace secure_storage { + // Helpers +Result ValueHash::create(Slice data) { + UInt256 hash; + if (data.size() != ::td::as_slice(hash).size()) { + return Status::Error("Wrong hash size"); + } + ::td::as_slice(hash).copy_from(data); + return ValueHash{hash}; +} + AesCbcState calc_aes_cbc_state(Slice seed) { UInt<512> hash; auto hash_slice = as_slice(hash); @@ -24,7 +38,7 @@ template Status data_view_for_each(DataView &data, F &&f) { const int64 step = 128 << 10; for (int64 i = 0, size = data.size(); i < size; i += step) { - TRY_RESULT(bytes, data.pread(i, std::min(step, size - i))); + TRY_RESULT(bytes, data.pread(i, min(step, size - i))); TRY_STATUS(f(std::move(bytes))); } return Status::OK(); @@ -42,6 +56,12 @@ Result calc_value_hash(DataView &data_view) { return ValueHash{res}; } +ValueHash calc_value_hash(Slice data) { + UInt256 res; + sha256(data, as_slice(res)); + return ValueHash{res}; +} + BufferSlice gen_random_prefix(int64 data_size) { BufferSlice buff(narrow_cast(((32 + 15 + data_size) & -16) - data_size)); Random::secure_bytes(buff.as_slice()); @@ -53,7 +73,7 @@ BufferSlice gen_random_prefix(int64 data_size) { FileDataView::FileDataView(FileFd &fd, int64 size) : fd_(fd), size_(size) { } -int64 FileDataView::size() { +int64 FileDataView::size() const { return size_; } @@ -68,7 +88,7 @@ Result FileDataView::pread(int64 offset, int64 size) { BufferSliceDataView::BufferSliceDataView(BufferSlice buffer_slice) : buffer_slice_(std::move(buffer_slice)) { } -int64 BufferSliceDataView::size() { +int64 BufferSliceDataView::size() const { return narrow_cast(buffer_slice_.size()); } Result BufferSliceDataView::pread(int64 offset, int64 size) { @@ -81,7 +101,7 @@ Result BufferSliceDataView::pread(int64 offset, int64 size) { ConcatDataView::ConcatDataView(DataView &left, DataView &right) : left_(left), right_(right) { } -int64 ConcatDataView::size() { +int64 ConcatDataView::size() const { return left_.size() + right_.size(); } Result ConcatDataView::pread(int64 offset, int64 size) { @@ -91,8 +111,8 @@ Result ConcatDataView::pread(int64 offset, int64 size) { } auto substr = [](DataView &slice, int64 offset, int64 size) -> Result { - auto l = std::max(int64{0}, offset); - auto r = std::min(slice.size(), offset + size); + auto l = max(int64{0}, offset); + auto r = min(slice.size(), offset + size); if (l >= r) { return BufferSlice(); } @@ -125,11 +145,11 @@ Slice Password::as_slice() const { // Secret namespace { uint8 secret_checksum(Slice secret) { - uint8 sum = 0; + uint32 sum = 0; for (uint8 c : secret) { sum += c; } - return static_cast(239 - sum); + return static_cast((255 + 239 - sum % 255) % 255); } } // namespace @@ -137,12 +157,17 @@ Result Secret::create(Slice secret) { if (secret.size() != 32) { return Status::Error("wrong secret size"); } - if (secret_checksum(secret) != 0) { - return Status::Error("Wrong cheksum"); + uint32 checksum = secret_checksum(secret); + if (checksum != 0) { + return Status::Error(PSLICE() << "Wrong cheksum " << checksum); } UInt256 res; td::as_slice(res).copy_from(secret); - return Secret{res}; + + UInt256 secret_sha256; + sha256(secret, ::td::as_slice(secret_sha256)); + auto hash = as(secret_sha256.raw); + return Secret{res, hash}; } Secret Secret::create_new() { @@ -150,7 +175,8 @@ Secret Secret::create_new() { auto secret_slice = td::as_slice(secret); Random::secure_bytes(secret_slice); auto checksum_diff = secret_checksum(secret_slice); - secret_slice.ubegin()[0] += checksum_diff; + uint8 new_byte = (static_cast(secret_slice.ubegin()[0]) + checksum_diff) % 255; + secret_slice.ubegin()[0] = new_byte; return create(secret_slice).move_as_ok(); } @@ -159,6 +185,14 @@ Slice Secret::as_slice() const { return as_slice(secret_); } +int64 Secret::get_hash() const { + return hash_; +} + +Secret Secret::clone() const { + return {secret_, hash_}; +} + EncryptedSecret Secret::encrypt(Slice key) { auto aes_cbc_state = calc_aes_cbc_state(key); UInt256 res; @@ -166,7 +200,7 @@ EncryptedSecret Secret::encrypt(Slice key) { return EncryptedSecret::create(td::as_slice(res)).move_as_ok(); } -Secret::Secret(UInt256 secret) : secret_(secret) { +Secret::Secret(UInt256 secret, int64 hash) : secret_(secret), hash_(hash) { } //EncryptedSecret @@ -207,7 +241,7 @@ Result Decryptor::append(BufferSlice data) { sha256_update(data.as_slice(), &sha256_state_); if (!skipped_prefix_) { to_skip_ = data.as_slice().ubegin()[0]; - size_t to_skip = std::min(to_skip_, data.size()); + size_t to_skip = min(to_skip_, data.size()); skipped_prefix_ = true; data = data.from_slice(data.as_slice().remove_prefix(to_skip)); } @@ -230,7 +264,7 @@ Encryptor::Encryptor(AesCbcState aes_cbc_state, DataView &data_view) : aes_cbc_state_(std::move(aes_cbc_state)), data_view_(data_view) { } -int64 Encryptor::size() { +int64 Encryptor::size() const { return data_view_.size(); } @@ -266,7 +300,8 @@ Result decrypt_value(const Secret &secret, const ValueHash &hash, S TRY_RESULT(decrypted_value, decryptor.append(BufferSlice(data))); TRY_RESULT(got_hash, decryptor.finish()); if (got_hash.as_slice() != hash.as_slice()) { - return Status::Error("Hash mismatch"); + return Status::Error(PSLICE() << "Hash mismatch " << format::as_hex_dump<4>(got_hash.as_slice()) << " " + << format::as_hex_dump<4>(hash.as_slice())); } return std::move(decrypted_value); } diff --git a/td/telegram/SecureStorage.h b/td/telegram/SecureStorage.h index 456cfed88..57e26e64e 100644 --- a/td/telegram/SecureStorage.h +++ b/td/telegram/SecureStorage.h @@ -4,32 +4,21 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#include "td/utils/Random.h" +#pragma once + #include "td/utils/buffer.h" +#include "td/utils/common.h" #include "td/utils/crypto.h" -#include "td/utils/format.h" -#include "td/utils/int_types.h" -#include "td/utils/Status.h" -#include "td/utils/optional.h" #include "td/utils/port/FileFd.h" +#include "td/utils/Slice.h" +#include "td/utils/Status.h" + +#include "td/actor/actor.h" namespace td { -// secureValueSendingStatePending = SecureValueSendingState; -// secureValueSendingStateFailed = SecureValueSendingState; -// -// secureValue key:string sending_state:SecureValueSendingState unencrypted_text:string data:string files:vector = SecureValue; -// -// inputSecureValue key:string unencrypted_text:string data:string files:vector = InputSecureValue; -// -// updateSecureValue value:SecureValue = Update; -// -// setSecureValue password:string value:InputSecureValue = SecureValue; -// getSecureValue password:string key:string = SecureValue; -// - // Types // Password -// Secret - 32 bytes with sum == 239 +// Secret - 32 bytes with sum % 255 == 239 // EncryptedSecret - encrypted secret // ValueHash - 32 bytes, sha256 from value // @@ -64,8 +53,9 @@ namespace secure_storage { // Helpers class ValueHash { public: - ValueHash(UInt256 hash) : hash_(hash) { + explicit ValueHash(UInt256 hash) : hash_(hash) { } + static Result create(Slice data); Slice as_slice() const { return td::as_slice(hash_); } @@ -76,7 +66,7 @@ class ValueHash { class DataView { public: - virtual int64 size() = 0; + virtual int64 size() const = 0; virtual Result pread(int64 offset, int64 size) = 0; virtual ~DataView() = default; }; @@ -85,7 +75,7 @@ class FileDataView : public DataView { public: FileDataView(FileFd &fd, int64 size); - int64 size() override; + int64 size() const override; Result pread(int64 offset, int64 size) override; private: @@ -95,8 +85,8 @@ class FileDataView : public DataView { class BufferSliceDataView : public DataView { public: - BufferSliceDataView(BufferSlice buffer_slice); - int64 size() override; + explicit BufferSliceDataView(BufferSlice buffer_slice); + int64 size() const override; Result pread(int64 offset, int64 size) override; private: @@ -106,7 +96,7 @@ class BufferSliceDataView : public DataView { class ConcatDataView : public DataView { public: ConcatDataView(DataView &left, DataView &right); - int64 size() override; + int64 size() const override; Result pread(int64 offset, int64 size) override; private: @@ -116,11 +106,12 @@ class ConcatDataView : public DataView { AesCbcState calc_aes_cbc_state(Slice seed); Result calc_value_hash(DataView &data_view); +ValueHash calc_value_hash(Slice data); BufferSlice gen_random_prefix(int64 data_size); class Password { public: - Password(std::string password); + explicit Password(std::string password); Slice as_slice() const; private: @@ -137,9 +128,13 @@ class Secret { Slice as_slice() const; EncryptedSecret encrypt(Slice key); + int64 get_hash() const; + Secret clone() const; + private: - Secret(UInt256 secret); + Secret(UInt256 secret, int64 hash); UInt256 secret_; + int64 hash_; }; class EncryptedSecret { @@ -149,14 +144,14 @@ class EncryptedSecret { Slice as_slice() const; private: - EncryptedSecret(UInt256 encrypted_secret); + explicit EncryptedSecret(UInt256 encrypted_secret); UInt256 encrypted_secret_; }; // Decryption class Decryptor { public: - Decryptor(AesCbcState aes_cbc_state); + explicit Decryptor(AesCbcState aes_cbc_state); Result append(BufferSlice data); Result finish(); @@ -171,7 +166,7 @@ class Decryptor { class Encryptor : public DataView { public: Encryptor(AesCbcState aes_cbc_state, DataView &data_view); - int64 size() override; + int64 size() const override; Result pread(int64 offset, int64 size) override; private: diff --git a/td/telegram/SecureValue.cpp b/td/telegram/SecureValue.cpp new file mode 100644 index 000000000..4f23aa026 --- /dev/null +++ b/td/telegram/SecureValue.cpp @@ -0,0 +1,448 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#include "td/telegram/SecureValue.h" + +#include "td/telegram/files/FileManager.h" +#include "td/telegram/td_api.h" +#include "td/telegram/telegram_api.h" + +#include "td/utils/misc.h" + +namespace td { + +SecureValueType get_secure_value_type(tl_object_ptr &&secure_value_type) { + CHECK(secure_value_type != nullptr); + switch (secure_value_type->get_id()) { + case telegram_api::secureValueTypePersonalDetails::ID: + return SecureValueType::PersonalDetails; + case telegram_api::secureValueTypePassport::ID: + return SecureValueType::Passport; + case telegram_api::secureValueTypeDriverLicense::ID: + return SecureValueType::DriverLicense; + case telegram_api::secureValueTypeIdentityCard::ID: + return SecureValueType::IdentityCard; + case telegram_api::secureValueTypeAddress::ID: + return SecureValueType::Address; + case telegram_api::secureValueTypeUtilityBill::ID: + return SecureValueType::UtilityBill; + case telegram_api::secureValueTypeBankStatement::ID: + return SecureValueType::BankStatement; + case telegram_api::secureValueTypeRentalAgreement::ID: + return SecureValueType::RentalAgreement; + case telegram_api::secureValueTypePhone::ID: + return SecureValueType::PhoneNumber; + case telegram_api::secureValueTypeEmail::ID: + return SecureValueType::EmailAddress; + default: + UNREACHABLE(); + return SecureValueType::None; + } +} + +SecureValueType get_secure_value_type_td_api(tl_object_ptr &&passport_data_type) { + CHECK(passport_data_type != nullptr); + switch (passport_data_type->get_id()) { + case td_api::passportDataTypePersonalDetails::ID: + return SecureValueType::PersonalDetails; + case td_api::passportDataTypePassport::ID: + return SecureValueType::Passport; + case td_api::passportDataTypeDriverLicense::ID: + return SecureValueType::DriverLicense; + case td_api::passportDataTypeIdentityCard::ID: + return SecureValueType::IdentityCard; + case td_api::passportDataTypeAddress::ID: + return SecureValueType::Address; + case td_api::passportDataTypeUtilityBill::ID: + return SecureValueType::UtilityBill; + case td_api::passportDataTypeBankStatement::ID: + return SecureValueType::BankStatement; + case td_api::passportDataTypeRentalAgreement::ID: + return SecureValueType::RentalAgreement; + case td_api::passportDataTypePhoneNumber::ID: + return SecureValueType::PhoneNumber; + case td_api::passportDataTypeEmailAddress::ID: + return SecureValueType::EmailAddress; + default: + UNREACHABLE(); + return SecureValueType::None; + } +} + +vector get_secure_value_types( + vector> &&secure_value_types) { + return transform(std::move(secure_value_types), get_secure_value_type); +} + +td_api::object_ptr get_passport_data_type_object(SecureValueType type) { + switch (type) { + case SecureValueType::PersonalDetails: + return td_api::make_object(); + case SecureValueType::Passport: + return td_api::make_object(); + case SecureValueType::DriverLicense: + return td_api::make_object(); + case SecureValueType::IdentityCard: + return td_api::make_object(); + case SecureValueType::Address: + return td_api::make_object(); + case SecureValueType::UtilityBill: + return td_api::make_object(); + case SecureValueType::BankStatement: + return td_api::make_object(); + case SecureValueType::RentalAgreement: + return td_api::make_object(); + case SecureValueType::PhoneNumber: + return td_api::make_object(); + case SecureValueType::EmailAddress: + return td_api::make_object(); + case SecureValueType::None: + default: + UNREACHABLE(); + return nullptr; + } +} + +td_api::object_ptr get_secure_value_type_telegram_object(SecureValueType type) { + switch (type) { + case SecureValueType::PersonalDetails: + return telegram_api::make_object(); + case SecureValueType::Passport: + return telegram_api::make_object(); + case SecureValueType::DriverLicense: + return telegram_api::make_object(); + case SecureValueType::IdentityCard: + return telegram_api::make_object(); + case SecureValueType::Address: + return telegram_api::make_object(); + case SecureValueType::UtilityBill: + return telegram_api::make_object(); + case SecureValueType::BankStatement: + return telegram_api::make_object(); + case SecureValueType::RentalAgreement: + return telegram_api::make_object(); + case SecureValueType::PhoneNumber: + return telegram_api::make_object(); + case SecureValueType::EmailAddress: + return telegram_api::make_object(); + case SecureValueType::None: + default: + UNREACHABLE(); + return nullptr; + } +} + +vector> get_passport_data_types_object( + const vector &types) { + return transform(types, get_passport_data_type_object); +} + +bool operator==(const SecureFile &lhs, const SecureFile &rhs) { + return lhs.file_id == rhs.file_id && lhs.file_hash == rhs.file_hash && lhs.encrypted_secret == rhs.encrypted_secret; +} + +bool operator!=(const SecureFile &lhs, const SecureFile &rhs) { + return !(lhs == rhs); +} + +SecureFile get_secure_file(FileManager *file_manager, tl_object_ptr &&secure_file_ptr) { + CHECK(secure_file_ptr != nullptr); + SecureFile result; + switch (secure_file_ptr->get_id()) { + case telegram_api::secureFileEmpty::ID: + break; + case telegram_api::secureFile::ID: { + auto secure_file = telegram_api::move_object_as(secure_file_ptr); + auto dc_id = secure_file->dc_id_; + if (!DcId::is_valid(dc_id)) { + LOG(ERROR) << "Wrong dc_id = " << dc_id; + break; + } + result.file_id = + file_manager->register_remote(FullRemoteFileLocation(FileType::SecureRaw, secure_file->id_, + secure_file->access_hash_, DcId::internal(dc_id)), + FileLocationSource::FromServer, {}, 0, 0, ""); + result.encrypted_secret = secure_file->secret_.as_slice().str(); + result.file_hash = secure_file->file_hash_.as_slice().str(); + break; + } + default: + UNREACHABLE(); + } + return result; +} + +vector get_secure_files(FileManager *file_manager, + vector> &&secure_files) { + vector results; + results.reserve(secure_files.size()); + for (auto &secure_file : secure_files) { + auto result = get_secure_file(file_manager, std::move(secure_file)); + if (result.file_id.is_valid()) { + results.push_back(std::move(result)); + } + } + return results; +} + +telegram_api::object_ptr get_input_secure_file_object(FileManager *file_manager, + const SecureFile &file) { + //TODO: + return nullptr; +} + +td_api::object_ptr get_encrypted_file_object(FileManager *file_manager, const SecureFile &file) { + return file_manager->get_file_object(file.file_id); +} + +vector> get_encrypted_files_object(FileManager *file_manager, + const vector &files) { + return transform(files, + [file_manager](const SecureFile &file) { return get_encrypted_file_object(file_manager, file); }); +} + +vector> get_input_secure_files_object( + FileManager *file_manager, const vector &file) { + //TODO: + return {}; +} + +bool operator==(const SecureData &lhs, const SecureData &rhs) { + return lhs.data == rhs.data && lhs.hash == rhs.hash && lhs.encrypted_secret == rhs.encrypted_secret; +} + +bool operator!=(const SecureData &lhs, const SecureData &rhs) { + return !(lhs == rhs); +} + +SecureData get_secure_data(tl_object_ptr &&secure_data) { + CHECK(secure_data != nullptr); + SecureData result; + result.data = secure_data->data_.as_slice().str(); + result.hash = secure_data->data_hash_.as_slice().str(); + result.encrypted_secret = secure_data->secret_.as_slice().str(); + return result; +} + +telegram_api::object_ptr get_secure_data_object(const SecureData &data) { + return telegram_api::make_object(BufferSlice(data.data), BufferSlice(data.hash), + BufferSlice(data.encrypted_secret)); +} + +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; +} + +bool operator!=(const EncryptedSecureValue &lhs, const EncryptedSecureValue &rhs) { + return !(lhs == rhs); +} + +EncryptedSecureValue get_encrypted_secure_value(FileManager *file_manager, + tl_object_ptr &&secure_value) { + EncryptedSecureValue result; + CHECK(secure_value != nullptr); + result.type = get_secure_value_type(std::move(secure_value->type_)); + if (secure_value->plain_data_ != nullptr) { + switch (secure_value->plain_data_->get_id()) { + case telegram_api::securePlainPhone::ID: + result.data.data = + std::move(static_cast(secure_value->plain_data_.get())->phone_); + break; + case telegram_api::securePlainEmail::ID: + result.data.data = + std::move(static_cast(secure_value->plain_data_.get())->email_); + break; + default: + UNREACHABLE(); + } + } + if (secure_value->data_ != nullptr) { + result.data = get_secure_data(std::move(secure_value->data_)); + } + result.files = get_secure_files(file_manager, std::move(secure_value->files_)); + if (secure_value->selfie_ != nullptr) { + result.selfie = get_secure_file(file_manager, std::move(secure_value->selfie_)); + } + 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)); + }); +} + +td_api::object_ptr get_encrypted_passport_data_object( + FileManager *file_manager, const EncryptedSecureValue &value) { + 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()); +} + +telegram_api::object_ptr get_input_secure_value_object( + FileManager *file_manager, const EncryptedSecureValue &value) { + bool is_plain = value.type == SecureValueType::PhoneNumber || value.type == SecureValueType::EmailAddress; + bool has_selfie = value.selfie.file_id.is_valid(); + int32 flags = 0; + tl_object_ptr plain_data; + if (is_plain) { + if (value.type == SecureValueType::PhoneNumber) { + plain_data = make_tl_object(value.data.data); + } else { + plain_data = make_tl_object(value.data.data); + } + flags |= telegram_api::inputSecureValue::PLAIN_DATA_MASK; + } else { + flags |= telegram_api::inputSecureValue::DATA_MASK; + } + if (!value.files.empty()) { + flags |= telegram_api::inputSecureValue::FILES_MASK; + } + if (has_selfie) { + flags |= telegram_api::inputSecureValue::SELFIE_MASK; + } + return telegram_api::make_object( + 0, get_secure_value_type_telegram_object(value.type), is_plain ? nullptr : get_secure_data_object(value.data), + get_input_secure_files_object(file_manager, value.files), std::move(plain_data), + has_selfie ? get_input_secure_file_object(file_manager, value.selfie) : nullptr); +} + +vector> get_encrypted_passport_data_object( + FileManager *file_manager, const vector &values) { + return transform(values, [file_manager](const EncryptedSecureValue &value) { + return get_encrypted_passport_data_object(file_manager, value); + }); +} + +bool operator==(const SecureCredentials &lhs, const SecureCredentials &rhs) { + return lhs.data == rhs.data && lhs.hash == rhs.hash && lhs.encrypted_secret == rhs.encrypted_secret; +} + +bool operator!=(const SecureCredentials &lhs, const SecureCredentials &rhs) { + return !(lhs == rhs); +} + +SecureCredentials get_secure_credentials(tl_object_ptr &&credentials) { + CHECK(credentials != nullptr); + SecureCredentials result; + result.data = credentials->data_.as_slice().str(); + result.hash = credentials->hash_.as_slice().str(); + result.encrypted_secret = credentials->secret_.as_slice().str(); + return result; +} + +td_api::object_ptr get_encrypted_credentials_object( + const SecureCredentials &credentials) { + return td_api::make_object(credentials.data, credentials.hash, + credentials.encrypted_secret); +} + +Result get_secure_value(td_api::object_ptr &&input_passport_data) { + if (input_passport_data == nullptr) { + return Status::Error(400, "InputPassportData must not be empty"); + } + + SecureValue res; + res.type = get_secure_value_type_td_api(std::move(input_passport_data->type_)); + res.data = std::move(input_passport_data->data_); + // res.files = TODO + return res; +} + +Result decrypt_secure_file(FileManager *file_manager, const secure_storage::Secret &secret, + const SecureFile &secure_file) { + return Status::Error("TODO"); +} + +Result> decrypt_secure_files(FileManager *file_manager, const secure_storage::Secret &secret, + const vector &secure_files) { + vector res; + res.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); + } + + return std::move(res); +} +Result decrypt_secure_data(const secure_storage::Secret &master_secret, const SecureData &secure_data) { + TRY_RESULT(hash, secure_storage::ValueHash::create(secure_data.hash)); + TRY_RESULT(encrypted_secret, secure_storage::EncryptedSecret::create(secure_data.encrypted_secret)); + TRY_RESULT(secret, encrypted_secret.decrypt(PSLICE() << master_secret.as_slice() << hash.as_slice())); + TRY_RESULT(value, secure_storage::decrypt_value(secret, hash, secure_data.data)); + return value.as_slice().str(); +} + +Result decrypt_encrypted_secure_value(FileManager *file_manager, const secure_storage::Secret &secret, + const EncryptedSecureValue &encrypted_secure_value) { + SecureValue res; + res.type = encrypted_secure_value.type; + switch (encrypted_secure_value.type) { + case SecureValueType::EmailAddress: + case SecureValueType::PhoneNumber: + res.data = encrypted_secure_value.data.data; + break; + default: { + TRY_RESULT(data, decrypt_secure_data(secret, encrypted_secure_value.data)); + res.data = std::move(data); + // TODO + //TRY_RESULT(files, decrypt_secure_files(file_manager, secret, encrypted_secure_value.files)); + //res.files = std::move(files); + break; + } + } + return std::move(res); +} + +SecureFile encrypt_secure_file(FileManager *file_manager, const secure_storage::Secret &master_secret, FileId file, + string &to_hash) { + //TODO: + return SecureFile{}; +} +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); }); +} +SecureData encrypt_secure_data(const secure_storage::Secret &master_secret, Slice data, string &to_hash) { + namespace ss = secure_storage; + auto secret = ss::Secret::create_new(); + auto encrypted = ss::encrypt_value(secret, data).move_as_ok(); + SecureData res; + res.encrypted_secret = + secret.encrypt(PSLICE() << master_secret.as_slice() << encrypted.hash.as_slice()).as_slice().str(); + res.data = encrypted.data.as_slice().str(); + res.hash = encrypted.hash.as_slice().str(); + to_hash.append(res.hash); + to_hash.append(secret.as_slice().str()); + return res; +} +EncryptedSecureValue encrypt_secure_value(FileManager *file_manager, const secure_storage::Secret &master_secret, + const SecureValue &secure_value) { + namespace ss = secure_storage; + EncryptedSecureValue res; + res.type = secure_value.type; + switch (res.type) { + case SecureValueType::EmailAddress: + case SecureValueType::PhoneNumber: + res.data = SecureData{secure_value.data, "", ""}; + res.hash = ss::calc_value_hash(secure_value.data).as_slice().str(); + break; + default: { + string to_hash; + res.data = encrypt_secure_data(master_secret, secure_value.data, to_hash); + // TODO + //res.files = encrypt_secure_files(file_manager, master_secret, secure_value.files, to_hash); + res.hash = ss::calc_value_hash(to_hash).as_slice().str(); + break; + } + } + return res; +} + +} // namespace td diff --git a/td/telegram/SecureValue.h b/td/telegram/SecureValue.h new file mode 100644 index 000000000..bec87cadc --- /dev/null +++ b/td/telegram/SecureValue.h @@ -0,0 +1,149 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once + +#include "td/telegram/td_api.h" +#include "td/telegram/telegram_api.h" + +#include "td/telegram/files/FileId.h" +#include "td/telegram/SecureStorage.h" + +#include "td/utils/common.h" +#include "td/utils/Status.h" + +namespace td { + +class FileManager; + +enum class SecureValueType { + None, + PersonalDetails, + Passport, + DriverLicense, + IdentityCard, + Address, + UtilityBill, + BankStatement, + RentalAgreement, + PhoneNumber, + EmailAddress +}; + +SecureValueType get_secure_value_type(tl_object_ptr &&secure_value_type); +SecureValueType get_secure_value_type_td_api(tl_object_ptr &&passport_data_type); + +vector get_secure_value_types( + vector> &&secure_value_types); + +td_api::object_ptr get_passport_data_type_object(SecureValueType type); +td_api::object_ptr get_secure_value_type_telegram_object(SecureValueType type); + +vector> get_passport_data_types_object( + const vector &types); + +struct SecureFile { + FileId file_id; + string file_hash; + string encrypted_secret; +}; + +bool operator==(const SecureFile &lhs, const SecureFile &rhs); +bool operator!=(const SecureFile &lhs, const SecureFile &rhs); + +SecureFile get_secure_file(FileManager *file_manager, tl_object_ptr &&secure_file_ptr); + +vector get_secure_files(FileManager *file_manager, + vector> &&secure_files); + +telegram_api::object_ptr get_input_secure_file_object(FileManager *file_manager, + const SecureFile &file); + +td_api::object_ptr get_encrypted_file_object(FileManager *file_manager, const SecureFile &file); + +vector> get_encrypted_files_object(FileManager *file_manager, + const vector &files); + +vector> get_input_secure_files_object( + FileManager *file_manager, const vector &file); + +struct SecureData { + string data; + string hash; + string encrypted_secret; +}; + +bool operator==(const SecureData &lhs, const SecureData &rhs); +bool operator!=(const SecureData &lhs, const SecureData &rhs); + +SecureData get_secure_data(tl_object_ptr &&secure_data); + +telegram_api::object_ptr get_secure_data_object(const SecureData &data); + +struct EncryptedSecureValue { + SecureValueType type = SecureValueType::None; + SecureData data; + vector files; + SecureFile selfie; + string hash; // memory only +}; + +bool operator==(const EncryptedSecureValue &lhs, const EncryptedSecureValue &rhs); +bool operator!=(const EncryptedSecureValue &lhs, const EncryptedSecureValue &rhs); + +EncryptedSecureValue get_encrypted_secure_value(FileManager *file_manager, + tl_object_ptr &&secure_value); + +vector get_encrypted_secure_values( + FileManager *file_manager, vector> &&secure_values); + +td_api::object_ptr get_encrypted_passport_data_object(FileManager *file_manager, + const EncryptedSecureValue &value); +telegram_api::object_ptr get_input_secure_value_object( + FileManager *file_manager, const EncryptedSecureValue &value); + +vector> get_encrypted_passport_data_object( + FileManager *file_manager, const vector &values); + +struct SecureCredentials { + string data; + string hash; + string encrypted_secret; +}; + +bool operator==(const SecureCredentials &lhs, const SecureCredentials &rhs); +bool operator!=(const SecureCredentials &lhs, const SecureCredentials &rhs); + +SecureCredentials get_secure_credentials(tl_object_ptr &&credentials); + +td_api::object_ptr get_encrypted_credentials_object(const SecureCredentials &credentials); + +class SecureValue { + public: + SecureValueType type; + string data; + vector files; +}; + +Result get_secure_value(td_api::object_ptr &&input_passport_data); + +Result decrypt_secure_file(FileManager *file_manager, const secure_storage::Secret &secret, + const SecureFile &secure_file); +Result> decrypt_secure_files(FileManager *file_manager, const secure_storage::Secret &secret, + const vector &secure_file); +Result decrypt_secure_data(const secure_storage::Secret &secret, const SecureData &secure_data); +Result decrypt_encrypted_secure_value(FileManager *file_manager, const secure_storage::Secret &secret, + const EncryptedSecureValue &encrypted_secure_value); + +SecureFile encrypt_secure_file(FileManager *file_manager, const secure_storage::Secret &master_secret, FileId file, + string &to_hash); +vector encrypt_secure_files(FileManager *file_manager, const secure_storage::Secret &master_secret, + vector files, string &to_hash); +SecureData encrypt_secure_data(const secure_storage::Secret &master_secret, Slice data, string &to_hash); +EncryptedSecureValue encrypt_secure_value(FileManager *file_manager, const secure_storage::Secret &master_secret, + const SecureValue &secure_value); + +} // namespace td diff --git a/td/telegram/SecureValue.hpp b/td/telegram/SecureValue.hpp new file mode 100644 index 000000000..827894381 --- /dev/null +++ b/td/telegram/SecureValue.hpp @@ -0,0 +1,107 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once + +#include "td/telegram/SecureValue.h" + +#include "td/telegram/files/FileId.hpp" + +#include "td/utils/tl_helpers.h" + +namespace td { + +template +void store(SecureFile file, StorerT &storer) { + store(file.file_id, storer); + store(file.file_hash, storer); + store(file.encrypted_secret, storer); +} + +template +void parse(SecureFile &file, ParserT &parser) { + parse(file.file_id, parser); + parse(file.file_hash, parser); + parse(file.encrypted_secret, parser); +} + +template +void store(const SecureData &data, StorerT &storer) { + store(data.data, storer); + store(data.hash, storer); + store(data.encrypted_secret, storer); +} + +template +void parse(SecureData &data, ParserT &parser) { + parse(data.data, parser); + parse(data.hash, parser); + parse(data.encrypted_secret, parser); +} + +template +void store(const SecureCredentials &credentials, StorerT &storer) { + store(credentials.data, storer); + store(credentials.hash, storer); + store(credentials.encrypted_secret, storer); +} + +template +void parse(SecureCredentials &credentials, ParserT &parser) { + parse(credentials.data, parser); + parse(credentials.hash, parser); + parse(credentials.encrypted_secret, parser); +} + +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(); + BEGIN_STORE_FLAGS(); + STORE_FLAG(has_data_hash); + STORE_FLAG(has_files); + STORE_FLAG(has_selfie); + END_STORE_FLAGS(); + store(value.type, storer); + if (has_data_hash) { + store(value.data, storer); + } else { + store(value.data.data, storer); + } + if (has_files) { + store(value.files, storer); + } + if (has_selfie) { + store(value.selfie, storer); + } +} + +template +void parse(EncryptedSecureValue &value, ParserT &parser) { + bool has_data_hash; + bool has_files; + bool has_selfie; + BEGIN_PARSE_FLAGS(); + PARSE_FLAG(has_data_hash); + PARSE_FLAG(has_files); + PARSE_FLAG(has_selfie); + END_PARSE_FLAGS(); + parse(value.type, parser); + if (has_data_hash) { + parse(value.data, parser); + } else { + parse(value.data.data, parser); + } + if (has_files) { + parse(value.files, parser); + } + if (has_selfie) { + parse(value.selfie, parser); + } +} + +} // namespace td diff --git a/td/telegram/StickersManager.cpp b/td/telegram/StickersManager.cpp index 8606d0d03..309d3ef85 100644 --- a/td/telegram/StickersManager.cpp +++ b/td/telegram/StickersManager.cpp @@ -79,9 +79,7 @@ class SearchStickersQuery : public Td::ResultHandler { public: void send(string emoji) { emoji_ = std::move(emoji); - int32 flags = 0; - send_query(G()->net_query_creator().create( - create_storer(telegram_api::messages_getStickers(flags, false /*ignored*/, emoji_, "")))); + send_query(G()->net_query_creator().create(create_storer(telegram_api::messages_getStickers(emoji_, 0)))); } void on_result(uint64 id, BufferSlice packet) override { @@ -781,6 +779,10 @@ class StickersManager::UploadStickerFileCallback : public FileManager::UploadCal UNREACHABLE(); } + void on_upload_secure_ok(FileId file_id, tl_object_ptr input_file) override { + UNREACHABLE(); + } + void on_upload_error(FileId file_id, Status error) override { send_closure_later(G()->stickers_manager(), &StickersManager::on_upload_sticker_file_error, file_id, std::move(error)); @@ -1283,11 +1285,11 @@ bool StickersManager::has_input_media(FileId sticker_file_id, bool is_secret) co CHECK(sticker != nullptr); auto file_view = td_->file_manager_->get_file_view(sticker_file_id); if (is_secret) { - if (file_view.is_encrypted()) { + if (file_view.is_encrypted_secret()) { if (file_view.has_remote_location() && !sticker->message_thumbnail.file_id.is_valid()) { return true; } - } else { + } else if (!file_view.is_encrypted()) { if (sticker->set_id != 0) { // stickers within a set can be sent by id and access_hash return true; @@ -1311,7 +1313,7 @@ SecretInputMedia StickersManager::get_secret_input_media(FileId sticker_file_id, const Sticker *sticker = get_sticker(sticker_file_id); CHECK(sticker != nullptr); auto file_view = td_->file_manager_->get_file_view(sticker_file_id); - if (file_view.is_encrypted()) { + if (file_view.is_encrypted_secret()) { if (file_view.has_remote_location()) { input_file = file_view.remote_location().as_input_encrypted_file(); } @@ -1321,11 +1323,13 @@ SecretInputMedia StickersManager::get_secret_input_media(FileId sticker_file_id, if (sticker->message_thumbnail.file_id.is_valid() && thumbnail.empty()) { return {}; } - } else { + } else if (!file_view.is_encrypted()) { if (sticker->set_id == 0) { // stickers without set can't be sent by id and access_hash return {}; } + } else { + return {}; } vector> attributes; @@ -1347,7 +1351,7 @@ SecretInputMedia StickersManager::get_secret_input_media(FileId sticker_file_id, make_tl_object(sticker->dimensions.width, sticker->dimensions.height)); } - if (file_view.is_encrypted()) { + if (file_view.is_encrypted_secret()) { auto &encryption_key = file_view.encryption_key(); return SecretInputMedia{std::move(input_file), make_tl_object( @@ -1356,6 +1360,7 @@ SecretInputMedia StickersManager::get_secret_input_media(FileId sticker_file_id, narrow_cast(file_view.size()), BufferSlice(encryption_key.key_slice()), BufferSlice(encryption_key.iv_slice()), std::move(attributes), "")}; } else { + CHECK(!file_view.is_encrypted()); auto &remote_location = file_view.remote_location(); CHECK(!remote_location.is_web()); // web stickers shouldn't have set_id return SecretInputMedia{nullptr, @@ -2829,7 +2834,7 @@ vector StickersManager::get_attached_sticker_sets(FileId file_id, Promise promise.set_error(Status::Error(5, "File not found")); return {}; } - if (!file_view.has_remote_location() || file_view.remote_location().is_encrypted() || + if (!file_view.has_remote_location() || !file_view.remote_location().is_document() || file_view.remote_location().is_web()) { promise.set_value(Unit()); return {}; @@ -2979,8 +2984,7 @@ Result> StickersManager::prepare_input_file( bool is_url = false; bool is_local = false; if (file_view.has_remote_location()) { - CHECK(!file_view.remote_location().is_encrypted()); - CHECK(!file_view.remote_location().is_photo()); + CHECK(file_view.remote_location().is_document()); } else { if (file_view.has_url()) { is_url = true; @@ -3347,7 +3351,7 @@ void StickersManager::set_sticker_position_in_set(const tl_object_ptrfile_manager_->get_file_view(file_id); - if (!file_view.has_remote_location() || file_view.remote_location().is_encrypted() || + if (!file_view.has_remote_location() || !file_view.remote_location().is_document() || file_view.remote_location().is_web()) { return promise.set_error(Status::Error(7, "Wrong sticker file specified")); } @@ -3365,7 +3369,7 @@ void StickersManager::remove_sticker_from_set(const tl_object_ptrfile_manager_->get_file_view(file_id); - if (!file_view.has_remote_location() || file_view.remote_location().is_encrypted() || + if (!file_view.has_remote_location() || !file_view.remote_location().is_document() || file_view.remote_location().is_web()) { return promise.set_error(Status::Error(7, "Wrong sticker file specified")); } @@ -3390,14 +3394,14 @@ vector StickersManager::get_attached_sticker_file_ids(const vectorauth_manager_->is_bot()) { @@ -3594,7 +3598,7 @@ int32 StickersManager::get_recent_stickers_hash(const vector &sticker_id CHECK(sticker != nullptr); auto file_view = td_->file_manager_->get_file_view(sticker_id); CHECK(file_view.has_remote_location()); - CHECK(!file_view.remote_location().is_encrypted()); + CHECK(file_view.remote_location().is_document()); CHECK(!file_view.remote_location().is_web()); auto id = static_cast(file_view.remote_location().get_id()); numbers.push_back(static_cast(id >> 32)); @@ -3678,14 +3682,14 @@ bool StickersManager::add_recent_sticker_impl(bool is_attached, FileId sticker_i promise.set_error(Status::Error(7, "Can save only sent stickers")); return false; } - if (file_view.remote_location().is_encrypted()) { - promise.set_error(Status::Error(7, "Can't save encrypted stickers")); - return false; - } if (file_view.remote_location().is_web()) { promise.set_error(Status::Error(7, "Can't save web stickers")); return false; } + if (!file_view.remote_location().is_document()) { + promise.set_error(Status::Error(7, "Can't save encrypted stickers")); + return false; + } need_update_recent_stickers_[is_attached] = true; @@ -3737,7 +3741,7 @@ void StickersManager::remove_recent_sticker(bool is_attached, const tl_object_pt // TODO invokeAfter auto file_view = td_->file_manager_->get_file_view(file_id); CHECK(file_view.has_remote_location()); - CHECK(!file_view.remote_location().is_encrypted()); + CHECK(file_view.remote_location().is_document()); CHECK(!file_view.remote_location().is_web()); td_->create_handler(std::move(promise)) ->send(is_attached, file_view.remote_location().as_input_document(), true); @@ -4023,15 +4027,15 @@ bool StickersManager::add_favorite_sticker_impl(FileId sticker_id, Promise auto file_view = td_->file_manager_->get_file_view(sticker_id); if (!file_view.has_remote_location()) { - promise.set_error(Status::Error(7, "Can fave only sent stickers")); - return false; - } - if (file_view.remote_location().is_encrypted()) { - promise.set_error(Status::Error(7, "Can't fave encrypted stickers")); + promise.set_error(Status::Error(7, "Can add to favorites only sent stickers")); return false; } if (file_view.remote_location().is_web()) { - promise.set_error(Status::Error(7, "Can't fave web stickers")); + promise.set_error(Status::Error(7, "Can't add to favorites web stickers")); + return false; + } + if (!file_view.remote_location().is_document()) { + promise.set_error(Status::Error(7, "Can't add to favorites encrypted stickers")); return false; } @@ -4082,7 +4086,7 @@ void StickersManager::remove_favorite_sticker(const tl_object_ptrfile_manager_->get_file_view(file_id); CHECK(file_view.has_remote_location()); - CHECK(!file_view.remote_location().is_encrypted()); + CHECK(file_view.remote_location().is_document()); CHECK(!file_view.remote_location().is_web()); td_->create_handler(std::move(promise)) ->send(file_view.remote_location().as_input_document(), true); @@ -4140,7 +4144,7 @@ vector StickersManager::get_sticker_emojis(const tl_object_ptr { } }; +class GetSecureValue : public NetQueryCallback { + public: + GetSecureValue(std::string password, SecureValueType type, Promise promise) + : password_(std::move(password)), type_(type), promise_(std::move(promise)) { + } + + private: + string password_; + SecureValueType type_; + Promise promise_; + optional encrypted_secure_value_; + optional secret_; + + void on_error(Status status) { + promise_.set_error(std::move(status)); + stop(); + } + + void on_secret(Result r_secret, bool dummy) { + LOG_IF(ERROR, r_secret.is_error()) << r_secret.error(); + LOG_IF(ERROR, r_secret.is_ok()) << r_secret.ok().get_hash(); + if (r_secret.is_error()) { + return on_error(r_secret.move_as_error()); + } + secret_ = r_secret.move_as_ok(); + loop(); + } + + void loop() override { + if (!encrypted_secure_value_ || !secret_) { + return; + } + promise_.set_result(decrypt_encrypted_secure_value(G()->td().get_actor_unsafe()->file_manager_.get(), *secret_, + *encrypted_secure_value_)); + stop(); + } + void start_up() override { + std::vector> vec; + vec.push_back(get_secure_value_type_telegram_object(type_)); + + auto query = G()->net_query_creator().create(create_storer(telegram_api::account_getSecureValue(std::move(vec)))); + + G()->net_query_dispatcher().dispatch_with_callback(std::move(query), actor_shared(this)); + + send_closure(G()->password_manager(), &PasswordManager::get_secure_secret, password_, optional(), + PromiseCreator::lambda([actor_id = actor_id(this)](Result r_secret) { + send_closure(actor_id, &GetSecureValue::on_secret, std::move(r_secret), true); + })); + } + + void on_result(NetQueryPtr query) override { + auto r_result = fetch_result(std::move(query)); + if (r_result.is_error()) { + return on_error(r_result.move_as_error()); + } + auto result = r_result.move_as_ok(); + if (result.size() != 1) { + return on_error(Status::Error(PSLICE() << "Expected vector of size 1 got " << result.size())); + } + LOG(ERROR) << to_string(result[0]); + encrypted_secure_value_ = + get_encrypted_secure_value(G()->td().get_actor_unsafe()->file_manager_.get(), std::move(result[0])); + loop(); + } +}; + +class SetSecureValue : public NetQueryCallback { + public: + SetSecureValue(string password, SecureValue secure_value, Promise promise) + : password_(std::move(password)), secure_value_(std::move(secure_value)), promise_(std::move(promise)) { + } + + private: + string password_; + SecureValue secure_value_; + Promise promise_; + optional secret_; + + enum class State { WaitSecret, WaitSetValue } state_ = State::WaitSecret; + + void on_error(Status status) { + promise_.set_error(std::move(status)); + stop(); + } + + void on_secret(Result r_secret, bool x) { + LOG_IF(ERROR, r_secret.is_error()) << r_secret.error(); + LOG_IF(ERROR, r_secret.is_ok()) << r_secret.ok().get_hash(); + if (r_secret.is_error()) { + return on_error(r_secret.move_as_error()); + } + secret_ = r_secret.move_as_ok(); + loop(); + } + + void start_up() override { + send_closure(G()->password_manager(), &PasswordManager::get_secure_secret, password_, optional(), + PromiseCreator::lambda([actor_id = actor_id(this)](Result r_secret) { + send_closure(actor_id, &SetSecureValue::on_secret, std::move(r_secret), true); + })); + } + + void loop() override { + if (state_ == State::WaitSecret) { + if (!secret_) { + return; + } + auto *file_manager = G()->td().get_actor_unsafe()->file_manager_.get(); + auto save_secure_value = telegram_api::account_saveSecureValue( + get_input_secure_value_object(file_manager, encrypt_secure_value(file_manager, *secret_, secure_value_)), + secret_.value().get_hash()); + LOG(ERROR) << to_string(save_secure_value); + auto query = G()->net_query_creator().create(create_storer(save_secure_value)); + + G()->net_query_dispatcher().dispatch_with_callback(std::move(query), actor_shared(this)); + state_ = State::WaitSetValue; + } + } + void on_result(NetQueryPtr query) override { + auto r_result = fetch_result(std::move(query)); + if (r_result.is_error()) { + return on_error(r_result.move_as_error()); + } + auto result = r_result.move_as_ok(); + LOG(ERROR) << to_string(result); + } +}; + /** Td **/ Td::Td(std::unique_ptr callback) : callback_(std::move(callback)) { } @@ -4400,6 +4532,11 @@ class Td::UploadFileCallback : public FileManager::UploadCallback { send_closure(G()->file_manager(), &FileManager::upload, file_id, nullptr, 0, 0); } + void on_upload_secure_ok(FileId file_id, tl_object_ptr input_file) override { + // cancel file upload of the file to allow next upload with the same file to succeed + send_closure(G()->file_manager(), &FileManager::upload, file_id, nullptr, 0, 0); + } + void on_upload_error(FileId file_id, Status error) override { } }; @@ -4544,6 +4681,7 @@ Status Td::init(DbKey key) { device_token_manager_ = create_actor("DeviceTokenManager", create_reference()); hashtag_hints_ = create_actor("HashtagHints", "text", create_reference()); password_manager_ = create_actor("PasswordManager", create_reference()); + G()->set_password_manager(password_manager_.get()); privacy_manager_ = create_actor("PrivacyManager", create_reference()); secret_chats_manager_ = create_actor("SecretChatsManager", create_reference()); G()->set_secret_chats_manager(secret_chats_manager_.get()); @@ -5847,7 +5985,7 @@ void Td::on_request(uint64 id, td_api::createCall &request) { }); if (!request.protocol_) { - return query_promise.set_error(Status::Error(5, "CallProtocol must not be empty")); + return query_promise.set_error(Status::Error(5, "Call protocol must not be empty")); } UserId user_id(request.user_id_); @@ -6809,6 +6947,96 @@ void Td::on_request(uint64 id, const td_api::deleteSavedCredentials &request) { CREATE_NO_ARGS_REQUEST(DeleteSavedCredentialsRequest); } +void Td::on_request(uint64 id, td_api::getPassportData &request) { + CHECK_AUTH(); + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.password_); + if (request.type_ == nullptr) { + return send_error_raw(id, 400, "Type must not be empty"); + } + create_actor("GetSecureValue", std::move(request.password_), + get_secure_value_type_td_api(std::move(request.type_)), + PromiseCreator::lambda([](Result r_value) { + LOG_IF(ERROR, r_value.is_error()) << r_value.error(); + LOG_IF(ERROR, r_value.is_ok()) << r_value.ok().data; + })) + .release(); +} + +void Td::on_request(uint64 id, td_api::setPassportData &request) { + CHECK_AUTH(); + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.password_); + auto r_secure_value = get_secure_value(std::move(request.value_)); + if (r_secure_value.is_error()) { + return send_closure(actor_id(this), &Td::send_error, id, r_secure_value.move_as_error()); + } + create_actor( + "SetSecureValue", std::move(request.password_), r_secure_value.move_as_ok(), + PromiseCreator::lambda([](Result result) { LOG_IF(ERROR, result.is_error()) << result.error(); })) + .release(); +} + +void Td::on_request(uint64 id, const td_api::deletePassportData &request) { + CHECK_AUTH(); + CHECK_IS_USER(); + LOG(FATAL) << "TODO"; +} + +void Td::on_request(uint64 id, td_api::sendPhoneNumberVerificationCode &request) { + CHECK_AUTH(); + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.phone_number_); + LOG(FATAL) << "TODO"; +} + +void Td::on_request(uint64 id, const td_api::resendPhoneNumberVerificationCode &request) { + CHECK_AUTH(); + CHECK_IS_USER(); + LOG(FATAL) << "TODO"; +} + +void Td::on_request(uint64 id, td_api::checkPhoneNumberVerificationCode &request) { + CHECK_AUTH(); + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.code_); + LOG(FATAL) << "TODO"; +} + +void Td::on_request(uint64 id, td_api::sendEmailAddressVerificationCode &request) { + CHECK_AUTH(); + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.email_address_); + LOG(FATAL) << "TODO"; +} + +void Td::on_request(uint64 id, const td_api::resendEmailAddressVerificationCode &request) { + CHECK_AUTH(); + CHECK_IS_USER(); + LOG(FATAL) << "TODO"; +} + +void Td::on_request(uint64 id, td_api::checkEmailAddressVerificationCode &request) { + CHECK_AUTH(); + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.code_); + LOG(FATAL) << "TODO"; +} + +void Td::on_request(uint64 id, td_api::getPassportAuthorizationForm &request) { + CHECK_AUTH(); + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.public_key_); + CLEAN_INPUT_STRING(request.scope_); + LOG(FATAL) << "TODO"; +} + +void Td::on_request(uint64 id, const td_api::sendPassportAuthorizationForm &request) { + CHECK_AUTH(); + CHECK_IS_USER(); + LOG(FATAL) << "TODO"; +} + void Td::on_request(uint64 id, const td_api::getSupportUser &request) { CHECK_AUTH(); CHECK_IS_USER(); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index aef2ab4ab..ce03f0e60 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -747,6 +747,28 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, const td_api::deleteSavedCredentials &request); + void on_request(uint64 id, td_api::getPassportData &request); + + void on_request(uint64 id, td_api::setPassportData &request); + + void on_request(uint64 id, const td_api::deletePassportData &request); + + void on_request(uint64 id, td_api::sendPhoneNumberVerificationCode &request); + + void on_request(uint64 id, const td_api::resendPhoneNumberVerificationCode &request); + + void on_request(uint64 id, td_api::checkPhoneNumberVerificationCode &request); + + void on_request(uint64 id, td_api::sendEmailAddressVerificationCode &request); + + void on_request(uint64 id, const td_api::resendEmailAddressVerificationCode &request); + + void on_request(uint64 id, td_api::checkEmailAddressVerificationCode &request); + + void on_request(uint64 id, td_api::getPassportAuthorizationForm &request); + + void on_request(uint64 id, const td_api::sendPassportAuthorizationForm &request); + void on_request(uint64 id, const td_api::getSupportUser &request); void on_request(uint64 id, const td_api::getWallpapers &request); diff --git a/td/telegram/UpdatesManager.cpp b/td/telegram/UpdatesManager.cpp index eb4f24fcb..aaa8f0db2 100644 --- a/td/telegram/UpdatesManager.cpp +++ b/td/telegram/UpdatesManager.cpp @@ -487,6 +487,8 @@ bool UpdatesManager::is_acceptable_message(const telegram_api::Message *message_ case telegram_api::messageActionPaymentSent::ID: case telegram_api::messageActionPaymentSentMe::ID: case telegram_api::messageActionScreenshotTaken::ID: + case telegram_api::messageActionSecureValuesSent::ID: + case telegram_api::messageActionSecureValuesSentMe::ID: break; case telegram_api::messageActionChatCreate::ID: { auto chat_create = static_cast(action); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index f0c10c93f..82646449b 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -934,6 +934,35 @@ class CliClient final : public Actor { return nullptr; } + static tl_object_ptr as_passport_data_type(string passport_data_type) { + if (passport_data_type == "address" || passport_data_type == "a") { + return make_tl_object(); + } + if (passport_data_type == "email" || passport_data_type == "e") { + return make_tl_object(); + } + if (passport_data_type == "phone" || passport_data_type == "p") { + return make_tl_object(); + } + return make_tl_object(); + } + static tl_object_ptr as_input_passport_data(string passport_data_type) { + return nullptr; + /* TODO + vector> files; + if (passport_data_type == "address" || passport_data_type == "a") { + return make_tl_object("cucumber lives here", std::move(files)); + } + if (passport_data_type == "email" || passport_data_type == "e") { + return make_tl_object("{todo}"); + } + if (passport_data_type == "phone" || passport_data_type == "p") { + return make_tl_object("{todo}"); + } + return make_tl_object("I am cucumber", std::move(files)); + */ + } + static td_api::object_ptr execute(tl_object_ptr f) { LOG(INFO) << "Execute request: " << to_string(f); auto res = ClientActor::execute(std::move(f)); @@ -1049,6 +1078,16 @@ class CliClient final : public Actor { send_request(make_tl_object()); } else if (op == "ctp" || op == "CreateTemporaryPassword") { send_request(make_tl_object(args, 60 * 6)); + } else if (op == "gpd") { + string password; + string passport_data_type; + std::tie(password, passport_data_type) = split(args); + send_request(make_tl_object(as_passport_data_type(passport_data_type), password)); + } else if (op == "spd") { + string password; + string passport_data_type; + std::tie(password, passport_data_type) = split(args); + send_request(make_tl_object(as_input_passport_data(passport_data_type), password)); } else if (op == "pdu" || op == "processDcUpdate") { string dc_id; string ip_port; diff --git a/td/telegram/files/FileLoader.cpp b/td/telegram/files/FileLoader.cpp index 8431aa855..a7d02824e 100644 --- a/td/telegram/files/FileLoader.cpp +++ b/td/telegram/files/FileLoader.cpp @@ -18,6 +18,7 @@ #include "td/utils/ScopeGuard.h" #include +#include namespace td { void FileLoader::set_resource_manager(ActorShared resource_manager) { @@ -176,7 +177,7 @@ Status FileLoader::do_loop() { } else { send_closure(delay_dispatcher_, &DelayDispatcher::send_with_callback_and_delay, std::move(query), std::move(callback), next_delay_); - next_delay_ = std::max(next_delay_ * 0.8, 0.003); + next_delay_ = max(next_delay_ * 0.8, 0.003); } } return Status::OK(); diff --git a/td/telegram/files/FileLoaderUtils.cpp b/td/telegram/files/FileLoaderUtils.cpp index 1e89cb72e..4bb9cb2f1 100644 --- a/td/telegram/files/FileLoaderUtils.cpp +++ b/td/telegram/files/FileLoaderUtils.cpp @@ -138,10 +138,10 @@ Result search_file(CSlice dir, CSlice name, int64 expected_size) { return res; } -const char *file_type_name[file_type_size] = {"thumbnails", "profile_photos", "photos", "voice", - "videos", "documents", "secret", "temp", - "stickers", "music", "animations", "secret_thumbnails", - "wallpapers", "video_notes"}; +const char *file_type_name[file_type_size] = {"thumbnails", "profile_photos", "photos", "voice", + "videos", "documents", "secret", "temp", + "stickers", "music", "animations", "secret_thumbnails", + "wallpapers", "video_notes", "passport_temp", "passport"}; string get_file_base_dir(const FileDirType &file_dir_type) { switch (file_dir_type) { diff --git a/td/telegram/files/FileLocation.h b/td/telegram/files/FileLocation.h index 7733b65d2..3fa19d5ce 100644 --- a/td/telegram/files/FileLocation.h +++ b/td/telegram/files/FileLocation.h @@ -45,6 +45,8 @@ enum class FileType : int8 { EncryptedThumbnail, Wallpaper, VideoNote, + SecureRaw, + Secure, Size, None }; @@ -79,6 +81,10 @@ inline FileType from_td_api(const td_api::FileType &file_type) { return FileType::Wallpaper; case td_api::fileTypeVideoNote::ID: return FileType::VideoNote; + case td_api::fileTypeSecure::ID: + return FileType::Secure; + case td_api::fileTypeSecureEncrypted::ID: + return FileType::SecureRaw; case td_api::fileTypeNone::ID: return FileType::None; default: @@ -117,6 +123,10 @@ inline tl_object_ptr as_td_api(FileType file_type) { return make_tl_object(); case FileType::VideoNote: return make_tl_object(); + case FileType::Secure: + return make_tl_object(); + case FileType::SecureRaw: + return make_tl_object(); case FileType::None: return make_tl_object(); default: @@ -135,6 +145,8 @@ inline FileDirType get_file_dir_type(FileType file_type) { case FileType::Temp: case FileType::Wallpaper: case FileType::EncryptedThumbnail: + case FileType::Secure: + case FileType::SecureRaw: return FileDirType::Secure; default: return FileDirType::Common; @@ -422,6 +434,8 @@ class FullRemoteFileLocation { case FileType::Animation: case FileType::Encrypted: case FileType::VideoNote: + case FileType::SecureRaw: + case FileType::Secure: return LocationType::Common; case FileType::None: case FileType::Size: @@ -571,9 +585,21 @@ class FullRemoteFileLocation { bool is_common() const { return location_type() == LocationType::Common; } - bool is_encrypted() const { + bool is_encrypted_secret() const { return file_type_ == FileType::Encrypted; } + bool is_encrypted_secure() const { + return file_type_ == FileType::Secure; + } + bool is_encrypted_any() const { + return is_encrypted_secret() || is_encrypted_secure(); + } + bool is_secure() const { + return file_type_ == FileType::SecureRaw || file_type_ == FileType::Secure; + } + bool is_document() const { + return is_common() && !is_secure() && !is_encrypted_secret(); + } tl_object_ptr as_input_web_file_location() const { CHECK(is_web()); @@ -584,8 +610,10 @@ class FullRemoteFileLocation { case LocationType::Photo: return make_tl_object(photo().volume_id_, photo().local_id_, photo().secret_); case LocationType::Common: - if (is_encrypted()) { + if (is_encrypted_secret()) { return make_tl_object(common().id_, common().access_hash_); + } else if (is_secure()) { + return make_tl_object(common().id_, common().access_hash_); } else { return make_tl_object(common().id_, common().access_hash_, 0); } @@ -599,7 +627,7 @@ class FullRemoteFileLocation { tl_object_ptr as_input_document() const { CHECK(is_common()); - LOG_IF(ERROR, is_encrypted()) << "Can't call as_input_document on an encrypted file"; + LOG_IF(ERROR, !is_document()) << "Can't call as_input_document on an encrypted file"; return make_tl_object(common().id_, common().access_hash_); } @@ -609,9 +637,13 @@ class FullRemoteFileLocation { } tl_object_ptr as_input_encrypted_file() const { - CHECK(is_encrypted()) << "Can't call as_input_encrypted_file on a non-encrypted file"; + CHECK(is_encrypted_secret()) << "Can't call as_input_encrypted_file on a non-encrypted file"; return make_tl_object(common().id_, common().access_hash_); } + tl_object_ptr as_input_secure_file() const { + CHECK(is_secure()) << "Can't call as_input_secure_file on a non-secure file"; + return make_tl_object(common().id_, common().access_hash_); + } // TODO: this constructor is just for immediate unserialize FullRemoteFileLocation() = default; diff --git a/td/telegram/files/FileManager.cpp b/td/telegram/files/FileManager.cpp index fcaa4ff1e..835e14b76 100644 --- a/td/telegram/files/FileManager.cpp +++ b/td/telegram/files/FileManager.cpp @@ -1887,6 +1887,12 @@ tl_object_ptr FileManager::get_file_object(FileId file_id, bool wi file_view.has_remote_location(), remote_size)); } +vector> FileManager::get_files_object(const vector &file_ids, + bool with_main_file_id) { + return transform(file_ids, + [this, with_main_file_id](FileId file_id) { return get_file_object(file_id, with_main_file_id); }); +} + Result FileManager::check_input_file_id(FileType type, Result result, bool is_encrypted, bool allow_zero) { TRY_RESULT(file_id, std::move(result)); @@ -2122,7 +2128,7 @@ void FileManager::on_upload_ok(QueryId query_id, FileType file_type, const Parti FileView file_view(file_node); string file_name = get_file_name(file_type, file_view.suggested_name()); - if (file_view.is_encrypted()) { + if (file_view.is_encrypted_secret()) { tl_object_ptr input_file; if (partial_remote.is_big_) { input_file = make_tl_object( @@ -2136,6 +2142,16 @@ void FileManager::on_upload_ok(QueryId query_id, FileType file_type, const Parti file_node->upload_pause_ = file_id; file_info->upload_callback_.reset(); } + } else if (file_view.is_secure()) { + tl_object_ptr input_file; + input_file = make_tl_object( + partial_remote.file_id_, partial_remote.part_count_, "" /*md5*/, BufferSlice() /*file_hash*/, + BufferSlice() /*encrypted_secret*/); + if (file_info->upload_callback_) { + file_info->upload_callback_->on_upload_secure_ok(file_id, std::move(input_file)); + file_node->upload_pause_ = file_id; + file_info->upload_callback_.reset(); + } } else { tl_object_ptr input_file; if (partial_remote.is_big_) { diff --git a/td/telegram/files/FileManager.h b/td/telegram/files/FileManager.h index 10f961c21..887349302 100644 --- a/td/telegram/files/FileManager.h +++ b/td/telegram/files/FileManager.h @@ -224,9 +224,21 @@ class FileView { } return FileType::Temp; } - bool is_encrypted() const { + bool is_encrypted_secret() const { return get_type() == FileType::Encrypted; } + bool is_encrypted_secure() const { + return get_type() == FileType::Secure; + } + bool is_secure() const { + return get_type() == FileType::Secure || get_type() == FileType::SecureRaw; + } + bool is_encrypted_any() const { + return is_encrypted_secret() || is_encrypted_secure(); + } + bool is_encrypted() const { + return is_encrypted_secret() || is_secure(); + } const FileEncryptionKey &encryption_key() const { return node_->encryption_key_; } @@ -266,6 +278,7 @@ class FileManager : public FileLoadManager::Callback { // Also upload may be resumed after some other merges. virtual void on_upload_ok(FileId file_id, tl_object_ptr input_file) = 0; virtual void on_upload_encrypted_ok(FileId file_id, tl_object_ptr input_file) = 0; + virtual void on_upload_secure_ok(FileId file_id, tl_object_ptr input_file) = 0; virtual void on_upload_error(FileId file_id, Status error) = 0; }; @@ -326,6 +339,7 @@ class FileManager : public FileLoadManager::Callback { FileView get_file_view(FileId file_id) const; FileView get_sync_file_view(FileId file_id); tl_object_ptr get_file_object(FileId file_id, bool with_main_file_id = true); + vector> get_files_object(const vector &file_ids, bool with_main_file_id = true); Result get_input_thumbnail_file_id(const tl_object_ptr &thumb_input_file, DialogId owner_dialog_id, bool is_encrypted) TD_WARN_UNUSED_RESULT; diff --git a/td/telegram/files/FileManager.hpp b/td/telegram/files/FileManager.hpp index 28f481308..be2a5cff2 100644 --- a/td/telegram/files/FileManager.hpp +++ b/td/telegram/files/FileManager.hpp @@ -40,7 +40,7 @@ void FileManager::store_file(FileId file_id, StorerT &storer, int32 ttl) const { bool has_expected_size = file_store_type == FileStoreType::Remote && file_view.size() == 0 && file_view.expected_size() != 0; if (file_store_type != FileStoreType::Empty) { - has_encryption_key = !file_view.empty() && file_view.is_encrypted(); + has_encryption_key = !file_view.empty() && file_view.is_encrypted_secret(); BEGIN_STORE_FLAGS(); STORE_FLAG(has_encryption_key); STORE_FLAG(has_expected_size); diff --git a/td/telegram/net/MtprotoHeader.cpp b/td/telegram/net/MtprotoHeader.cpp index 3c41e2d1d..625b58265 100644 --- a/td/telegram/net/MtprotoHeader.cpp +++ b/td/telegram/net/MtprotoHeader.cpp @@ -18,7 +18,7 @@ class HeaderStorer { } template void store(StorerT &storer) const { - constexpr int32 LAYER = 76; + constexpr int32 LAYER = 78; using td::store; // invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; diff --git a/tdtl/td/tl/tl_file_utils.cpp b/tdtl/td/tl/tl_file_utils.cpp index bc79d7254..1e423e472 100644 --- a/tdtl/td/tl/tl_file_utils.cpp +++ b/tdtl/td/tl/tl_file_utils.cpp @@ -8,7 +8,6 @@ #include #include -#include namespace td { namespace tl { diff --git a/tdutils/td/utils/Random.cpp b/tdutils/td/utils/Random.cpp index 9143470b0..d6fb6bc09 100644 --- a/tdutils/td/utils/Random.cpp +++ b/tdutils/td/utils/Random.cpp @@ -13,6 +13,7 @@ #include #endif +#include #include #include #include diff --git a/tdutils/td/utils/crypto.cpp b/tdutils/td/utils/crypto.cpp index e77e89181..52b569e26 100644 --- a/tdutils/td/utils/crypto.cpp +++ b/tdutils/td/utils/crypto.cpp @@ -12,6 +12,7 @@ #include "td/utils/port/RwMutex.h" #include "td/utils/port/thread_local.h" #include "td/utils/Random.h" +#include "td/utils/ScopeGuard.h" #if TD_HAVE_OPENSSL #include @@ -485,7 +486,6 @@ Result rsa_encrypt_pkcs1_oaep(Slice public_key, Slice data) { } BufferSlice res(outlen); if (EVP_PKEY_encrypt(ctx, res.as_slice().ubegin(), &outlen, data.ubegin(), data.size()) <= 0) { - // ERR_print_errors_fp(stderr); return Status::Error("Cannot encrypt"); } return std::move(res); diff --git a/tdutils/test/pq.cpp b/tdutils/test/pq.cpp index 5210cc263..c70527e10 100644 --- a/tdutils/test/pq.cpp +++ b/tdutils/test/pq.cpp @@ -115,4 +115,4 @@ TEST(CryptoPQ, generated_slow) { test_pq(query.first, query.second); } } -#endif \ No newline at end of file +#endif diff --git a/test/secure_storage.cpp b/test/secure_storage.cpp index 3f4a540c0..0a65f9042 100644 --- a/test/secure_storage.cpp +++ b/test/secure_storage.cpp @@ -6,6 +6,7 @@ // #include "td/utils/buffer.h" #include "td/utils/filesystem.h" +#include "td/utils/logging.h" #include "td/utils/port/path.h" #include "td/utils/tests.h"