Layer 78. Initial Telegram Passport support.

GitOrigin-RevId: 197994bcf62a76cd963f32a8dd7f5951d7b6588b
This commit is contained in:
Arseny Smirnov 2018-03-27 16:11:15 +03:00
parent ccf8064821
commit fb79d6f95a
40 changed files with 1694 additions and 159 deletions

View File

@ -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

View File

@ -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<file> = 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<InputFile> = InputPassportData;
//@class PassportAuthorizationForm Contains information about requested Telegram Passport authorization form @data Available data
passportAuthorizationForm id:int32 data:vector<PassportData> = 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<file> 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<PassportDataType> = 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<EncryptedPassportData> 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;

Binary file not shown.

View File

@ -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<BotInfo> = 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<SecureValue> credentials:SecureCredentialsEncrypted = MessageAction;
messageActionSecureValuesSent#d95c6154 types:Vector<SecureValueType> = 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<Document> = messages.Stickers;
messages.stickers#e4599bbd hash:int stickers:Vector<Document> = messages.Stickers;
stickerPack#12b299d4 emoticon:string documents:Vector<long> = StickerPack;
@ -468,12 +471,12 @@ authorization#7bf2e6f6 hash:long flags:int device_model:string platform:string s
account.authorizations#1250abde authorizations:Vector<Authorization> = 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<StickerSetCovered> = 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<SecureFile> 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<InputSecureFile> 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<SecureValueType> values:Vector<SecureValue> users:Vector<User> 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<SecureValueType> = Vector<SecureValue>;
account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long = SecureValue;
account.deleteSecureValue#b880bc4b types:Vector<SecureValueType> = 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<SecureValueHash> 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<InputUser> = Vector<User>;
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<long>;
messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool;
messages.readMessageContents#36a73f77 id:Vector<int> = 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<MessageEntity> = MessageMedia;
messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite;

Binary file not shown.

View File

@ -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<uint64>(file_view.remote_location().get_id());
numbers.push_back(static_cast<uint32>(id >> 32));
numbers.push_back(static_cast<uint32>(id & 0xFFFFFFFF));
@ -598,14 +597,14 @@ bool AnimationsManager::add_saved_animation_impl(FileId animation_id, Promise<Un
promise.set_error(Status::Error(7, "Can save only sent animations"));
return false;
}
if (file_view.remote_location().is_encrypted()) {
promise.set_error(Status::Error(7, "Can't save encrypted animations"));
return false;
}
if (file_view.remote_location().is_web()) {
promise.set_error(Status::Error(7, "Can't save web animations"));
return false;
}
if (!file_view.remote_location().is_document()) {
promise.set_error(Status::Error(7, "Can't save encrypted animations"));
return false;
}
auto it = std::find(saved_animation_ids_.begin(), saved_animation_ids_.end(), animation_id);
if (it == saved_animation_ids_.end()) {
@ -654,7 +653,7 @@ void AnimationsManager::remove_saved_animation(const tl_object_ptr<td_api::Input
// 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<SaveGifQuery>(std::move(promise))->send(file_view.remote_location().as_input_document(), true);

View File

@ -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"

View File

@ -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 {

View File

@ -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 {

View File

@ -2310,6 +2310,9 @@ class ContactsManager::UploadProfilePhotoCallback : public FileManager::UploadCa
void on_upload_encrypted_ok(FileId file_id, tl_object_ptr<telegram_api::InputEncryptedFile> input_file) override {
UNREACHABLE();
}
void on_upload_secure_ok(FileId file_id, tl_object_ptr<telegram_api::InputSecureFile> 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<telegram_api::user>(
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);

View File

@ -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<MessagesManager> messages_manager) {
messages_manager_ = messages_manager;
}
ActorId<PasswordManager> password_manager() const {
return password_manager_;
}
void set_password_manager(ActorId<PasswordManager> password_manager) {
password_manager_ = password_manager;
}
ActorId<SecretChatsManager> secret_chats_manager() const {
return secret_chats_manager_;
}
@ -291,6 +298,7 @@ class Global : public ActorContext {
ActorId<ContactsManager> contacts_manager_;
ActorId<FileManager> file_manager_;
ActorId<MessagesManager> messages_manager_;
ActorId<PasswordManager> password_manager_;
ActorId<SecretChatsManager> secret_chats_manager_;
ActorId<CallManager> call_manager_;
ActorId<StickersManager> stickers_manager_;

View File

@ -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"

View File

@ -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<telegram_api::InputSecureFile> 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<telegram_api::InputEncryptedFile> input_file) override {
UNREACHABLE();
}
void on_upload_secure_ok(FileId file_id, tl_object_ptr<telegram_api::InputSecureFile> 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<telegram_api::InputEncryptedFile> input_file) override {
UNREACHABLE();
}
void on_upload_secure_ok(FileId file_id, tl_object_ptr<telegram_api::InputSecureFile> 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<const MessagePassportDataSent *>(content);
store(m->types, storer);
break;
}
case MessagePassportDataReceived::ID: {
auto m = static_cast<const MessagePassportDataReceived *>(content);
store(m->values, storer);
store(m->credentials, storer);
break;
}
default:
UNREACHABLE();
}
@ -3901,6 +3922,19 @@ static void parse(unique_ptr<MessageContent> &content, ParserT &parser) {
content = std::move(m);
break;
}
case MessagePassportDataSent::ID: {
auto m = make_unique<MessagePassportDataSent>();
parse(m->types, parser);
content = std::move(m);
break;
}
case MessagePassportDataReceived::ID: {
auto m = make_unique<MessagePassportDataReceived>();
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<td_api::MessageContent> MessagesManager::get_message_content_objec
const MessageWebsiteConnected *m = static_cast<const MessageWebsiteConnected *>(content);
return make_tl_object<td_api::messageWebsiteConnected>(m->domain_name);
}
case MessagePassportDataSent::ID: {
const MessagePassportDataSent *m = static_cast<const MessagePassportDataSent *>(content);
return make_tl_object<td_api::messagePassportDataSent>(get_passport_data_types_object(m->types));
}
case MessagePassportDataReceived::ID: {
const MessagePassportDataReceived *m = static_cast<const MessagePassportDataReceived *>(content);
return make_tl_object<td_api::messagePassportDataReceived>(
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<telegram_api::InputMedia> 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, vector<int
auto layer = td_->contacts_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<MessageContent> 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<MessageContent> 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<MessageContent> MessagesManager::get_message_action_content(
auto bot_allowed = move_tl_object_as<telegram_api::messageActionBotAllowed>(action);
return make_unique<MessageWebsiteConnected>(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<telegram_api::messageActionSecureValuesSent>(action);
return make_unique<MessagePassportDataSent>(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<telegram_api::messageActionSecureValuesSentMe>(action);
return make_unique<MessagePassportDataReceived>(
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<const MessagePassportDataSent *>(old_content.get());
auto new_ = static_cast<const MessagePassportDataSent *>(new_content.get());
if (old_->types != new_->types) {
need_update = true;
}
break;
}
case MessagePassportDataReceived::ID: {
auto old_ = static_cast<const MessagePassportDataReceived *>(old_content.get());
auto new_ = static_cast<const MessagePassportDataReceived *>(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:

View File

@ -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<SecureValueType> types;
MessagePassportDataSent() = default;
explicit MessagePassportDataSent(vector<SecureValueType> &&types) : types(std::move(types)) {
}
static const int32 ID = 38;
int32 get_id() const override {
return ID;
}
};
class MessagePassportDataReceived : public MessageContent {
public:
vector<EncryptedSecureValue> values;
SecureCredentials credentials;
MessagePassportDataReceived() = default;
MessagePassportDataReceived(vector<EncryptedSecureValue> &&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;

View File

@ -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<int64> hash,
Promise<secure_storage::Secret> 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<int64> hash,
Promise<secure_storage::Secret> 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<PasswordFullState> 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<bool> 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<TempState> promise) /*const*/ {
promise.set_value(temp_password_state_.as_td_api());
}
@ -135,20 +183,61 @@ void PasswordManager::on_finish_create_temp_password(Result<TempPasswordState> r
create_temp_password_promise_.set_value(temp_password_state_.as_td_api());
}
void PasswordManager::get_recovery_email_address(string password,
Promise<tl_object_ptr<td_api::recoveryEmailAddress>> promise) {
void PasswordManager::get_full_state(string password, Promise<PasswordFullState> promise) {
do_get_state(PromiseCreator::lambda([password = std::move(password), promise = std::move(promise),
actor_id = actor_id(this)](Result<PasswordState> 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<tl_object_ptr<td_api::passwordRecoveryInfo>> promise) {
send_with_promise(G()->net_query_creator().create(create_storer(telegram_api::auth_requestPasswordRecovery())),
void PasswordManager::do_get_full_state(string password, PasswordState state, Promise<PasswordFullState> 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<NetQueryPtr> r_query) mutable {
promise.set_result([&]() -> Result<PasswordFullState> {
TRY_RESULT(query, std::move(r_query));
TRY_RESULT(result, fetch_result<telegram_api::account_getPasswordSettings>(std::move(query)));
PasswordPrivateState private_state;
private_state.email = result->email_;
namespace ss = secure_storage;
auto r_secret = [&]() -> Result<ss::Secret> {
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<tl_object_ptr<td_api::recoveryEmailAddress>> promise) {
get_full_state(
password,
PromiseCreator::lambda([password, promise = std::move(promise)](Result<PasswordFullState> 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<td_api::recoveryEmailAddress>(state.private_state.email));
}));
}
void PasswordManager::request_password_recovery(
Promise<tl_object_ptr<td_api::emailAddressAuthenticationCodeInfo>> promise) {
send_with_promise(
G()->net_query_creator().create(create_storer(telegram_api::auth_requestPasswordRecovery())),
PromiseCreator::lambda([promise = std::move(promise)](Result<NetQueryPtr> r_query) mutable {
if (r_query.is_error()) {
return promise.set_error(r_query.move_as_error());
@ -158,7 +247,7 @@ void PasswordManager::request_password_recovery(Promise<tl_object_ptr<td_api::pa
return promise.set_error(r_result.move_as_error());
}
auto result = r_result.move_as_ok();
return promise.set_value(make_tl_object<td_api::passwordRecoveryInfo>(result->email_pattern_));
return promise.set_value(make_tl_object<td_api::emailAddressAuthenticationCodeInfo>(result->email_pattern_));
}));
}
@ -177,23 +266,6 @@ void PasswordManager::recover_password(string code, Promise<State> promise) {
}));
}
void PasswordManager::do_get_recovery_email_address(string password, PasswordState state,
Promise<tl_object_ptr<td_api::recoveryEmailAddress>> 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<NetQueryPtr> r_query) mutable {
if (r_query.is_error()) {
return promise.set_error(r_query.move_as_error());
}
auto r_result = fetch_result<telegram_api::account_getPasswordSettings>(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<td_api::recoveryEmailAddress>(result->email_));
}));
}
void PasswordManager::update_password_settings(UpdateSettings update_settings, Promise<State> promise) {
auto result_promise = PromiseCreator::lambda(
[actor_id = actor_id(this), promise = std::move(promise)](Result<bool> 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<PasswordState> r_state) mutable {
update_settings = std::move(update_settings)](Result<PasswordFullState> 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<bool> promise) {
auto state = std::move(full_state.state);
auto private_state = std::move(full_state.private_state);
auto new_settings = make_tl_object<telegram_api::account_passwordInputSettings>();
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<PasswordState> 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<PasswordState> 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<PasswordState> 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();

View File

@ -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<State> promise);
void get_recovery_email_address(string password, Promise<tl_object_ptr<td_api::recoveryEmailAddress>> promise);
void request_password_recovery(Promise<tl_object_ptr<td_api::passwordRecoveryInfo>> promise);
void request_password_recovery(Promise<tl_object_ptr<td_api::emailAddressAuthenticationCodeInfo>> promise);
void recover_password(string code, Promise<State> promise);
void get_secure_secret(string password, optional<int64> hash, Promise<secure_storage::Secret> promise);
void get_temp_password_state(Promise<TempState> promise) /*const*/;
void create_temp_password(string password, int32 timeout, Promise<TempState> 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<td_api::passwordState>(has_password, password_hint, has_recovery_email_address,
unconfirmed_recovery_email_address_pattern);
}
};
struct PasswordPrivateState {
string email;
optional<secure_storage::Secret> 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<secure_storage::Secret> secret_;
TempPasswordState temp_password_state_;
Promise<TempState> create_temp_password_promise_;
void update_password_settings(UpdateSettings update_settings, Promise<State> promise);
void do_update_password_settings(UpdateSettings update_settings, PasswordState state, Promise<bool> promise);
void do_update_password_settings(UpdateSettings update_settings, PasswordFullState full_state, Promise<bool> promise);
void do_get_state(Promise<PasswordState> promise);
void do_get_recovery_email_address(string password, PasswordState state,
Promise<tl_object_ptr<td_api::recoveryEmailAddress>> promise);
void get_full_state(string password, Promise<PasswordFullState> promise);
void do_get_secure_secret(bool recursive, string passwod, optional<int64>, Promise<secure_storage::Secret> promise);
void do_get_full_state(string password, PasswordState state, Promise<PasswordFullState> promise);
void cache_secret(secure_storage::Secret secret);
void do_create_temp_password(string password, int32 timeout, PasswordState &&password_state,
Promise<TempPasswordState> promise);

View File

@ -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;
}

View File

@ -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> 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 <class F>
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<ValueHash> 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<size_t>(((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<BufferSlice> 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<int64>(buffer_slice_.size());
}
Result<BufferSlice> BufferSliceDataView::pread(int64 offset, int64 size) {
@ -81,7 +101,7 @@ Result<BufferSlice> 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<BufferSlice> ConcatDataView::pread(int64 offset, int64 size) {
@ -91,8 +111,8 @@ Result<BufferSlice> ConcatDataView::pread(int64 offset, int64 size) {
}
auto substr = [](DataView &slice, int64 offset, int64 size) -> Result<BufferSlice> {
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<uint8>(239 - sum);
return static_cast<uint8>((255 + 239 - sum % 255) % 255);
}
} // namespace
@ -137,12 +157,17 @@ Result<Secret> 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<int64>(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<uint32>(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<BufferSlice> 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<BufferSlice> 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);
}

View File

@ -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<File> = SecureValue;
//
// inputSecureValue key:string unencrypted_text:string data:string files:vector<InputFile> = 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<ValueHash> 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<BufferSlice> 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<BufferSlice> 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<BufferSlice> 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<BufferSlice> pread(int64 offset, int64 size) override;
private:
@ -116,11 +106,12 @@ class ConcatDataView : public DataView {
AesCbcState calc_aes_cbc_state(Slice seed);
Result<ValueHash> 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<BufferSlice> append(BufferSlice data);
Result<ValueHash> 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<BufferSlice> pread(int64 offset, int64 size) override;
private:

448
td/telegram/SecureValue.cpp Normal file
View File

@ -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<telegram_api::SecureValueType> &&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<td_api::PassportDataType> &&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<SecureValueType> get_secure_value_types(
vector<tl_object_ptr<telegram_api::SecureValueType>> &&secure_value_types) {
return transform(std::move(secure_value_types), get_secure_value_type);
}
td_api::object_ptr<td_api::PassportDataType> get_passport_data_type_object(SecureValueType type) {
switch (type) {
case SecureValueType::PersonalDetails:
return td_api::make_object<td_api::passportDataTypePersonalDetails>();
case SecureValueType::Passport:
return td_api::make_object<td_api::passportDataTypePassport>();
case SecureValueType::DriverLicense:
return td_api::make_object<td_api::passportDataTypeDriverLicense>();
case SecureValueType::IdentityCard:
return td_api::make_object<td_api::passportDataTypeIdentityCard>();
case SecureValueType::Address:
return td_api::make_object<td_api::passportDataTypeAddress>();
case SecureValueType::UtilityBill:
return td_api::make_object<td_api::passportDataTypeUtilityBill>();
case SecureValueType::BankStatement:
return td_api::make_object<td_api::passportDataTypeBankStatement>();
case SecureValueType::RentalAgreement:
return td_api::make_object<td_api::passportDataTypeRentalAgreement>();
case SecureValueType::PhoneNumber:
return td_api::make_object<td_api::passportDataTypePhoneNumber>();
case SecureValueType::EmailAddress:
return td_api::make_object<td_api::passportDataTypeEmailAddress>();
case SecureValueType::None:
default:
UNREACHABLE();
return nullptr;
}
}
td_api::object_ptr<telegram_api::SecureValueType> get_secure_value_type_telegram_object(SecureValueType type) {
switch (type) {
case SecureValueType::PersonalDetails:
return telegram_api::make_object<telegram_api::secureValueTypePersonalDetails>();
case SecureValueType::Passport:
return telegram_api::make_object<telegram_api::secureValueTypePassport>();
case SecureValueType::DriverLicense:
return telegram_api::make_object<telegram_api::secureValueTypeDriverLicense>();
case SecureValueType::IdentityCard:
return telegram_api::make_object<telegram_api::secureValueTypeIdentityCard>();
case SecureValueType::Address:
return telegram_api::make_object<telegram_api::secureValueTypeAddress>();
case SecureValueType::UtilityBill:
return telegram_api::make_object<telegram_api::secureValueTypeUtilityBill>();
case SecureValueType::BankStatement:
return telegram_api::make_object<telegram_api::secureValueTypeBankStatement>();
case SecureValueType::RentalAgreement:
return telegram_api::make_object<telegram_api::secureValueTypeRentalAgreement>();
case SecureValueType::PhoneNumber:
return telegram_api::make_object<telegram_api::secureValueTypePhone>();
case SecureValueType::EmailAddress:
return telegram_api::make_object<telegram_api::secureValueTypeEmail>();
case SecureValueType::None:
default:
UNREACHABLE();
return nullptr;
}
}
vector<td_api::object_ptr<td_api::PassportDataType>> get_passport_data_types_object(
const vector<SecureValueType> &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<telegram_api::SecureFile> &&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<telegram_api::secureFile>(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<SecureFile> get_secure_files(FileManager *file_manager,
vector<tl_object_ptr<telegram_api::SecureFile>> &&secure_files) {
vector<SecureFile> 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<telegram_api::InputSecureFile> get_input_secure_file_object(FileManager *file_manager,
const SecureFile &file) {
//TODO:
return nullptr;
}
td_api::object_ptr<td_api::file> get_encrypted_file_object(FileManager *file_manager, const SecureFile &file) {
return file_manager->get_file_object(file.file_id);
}
vector<td_api::object_ptr<td_api::file>> get_encrypted_files_object(FileManager *file_manager,
const vector<SecureFile> &files) {
return transform(files,
[file_manager](const SecureFile &file) { return get_encrypted_file_object(file_manager, file); });
}
vector<telegram_api::object_ptr<telegram_api::InputSecureFile>> get_input_secure_files_object(
FileManager *file_manager, const vector<SecureFile> &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<telegram_api::secureData> &&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<telegram_api::secureData> get_secure_data_object(const SecureData &data) {
return telegram_api::make_object<telegram_api::secureData>(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<telegram_api::secureValue> &&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<telegram_api::securePlainPhone *>(secure_value->plain_data_.get())->phone_);
break;
case telegram_api::securePlainEmail::ID:
result.data.data =
std::move(static_cast<telegram_api::securePlainEmail *>(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<EncryptedSecureValue> get_encrypted_secure_values(
FileManager *file_manager, vector<tl_object_ptr<telegram_api::secureValue>> &&secure_values) {
return transform(std::move(secure_values), [file_manager](tl_object_ptr<telegram_api::secureValue> &&secure_value) {
return get_encrypted_secure_value(file_manager, std::move(secure_value));
});
}
td_api::object_ptr<td_api::encryptedPassportData> get_encrypted_passport_data_object(
FileManager *file_manager, const EncryptedSecureValue &value) {
bool is_plain = value.data.hash.empty();
return td_api::make_object<td_api::encryptedPassportData>(
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<telegram_api::inputSecureValue> 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<telegram_api::SecurePlainData> plain_data;
if (is_plain) {
if (value.type == SecureValueType::PhoneNumber) {
plain_data = make_tl_object<telegram_api::securePlainPhone>(value.data.data);
} else {
plain_data = make_tl_object<telegram_api::securePlainEmail>(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<telegram_api::inputSecureValue>(
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<td_api::object_ptr<td_api::encryptedPassportData>> get_encrypted_passport_data_object(
FileManager *file_manager, const vector<EncryptedSecureValue> &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<telegram_api::secureCredentialsEncrypted> &&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<td_api::encryptedCredentials> get_encrypted_credentials_object(
const SecureCredentials &credentials) {
return td_api::make_object<td_api::encryptedCredentials>(credentials.data, credentials.hash,
credentials.encrypted_secret);
}
Result<SecureValue> get_secure_value(td_api::object_ptr<td_api::inputPassportData> &&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<FileId> decrypt_secure_file(FileManager *file_manager, const secure_storage::Secret &secret,
const SecureFile &secure_file) {
return Status::Error("TODO");
}
Result<vector<FileId>> decrypt_secure_files(FileManager *file_manager, const secure_storage::Secret &secret,
const vector<SecureFile> &secure_files) {
vector<FileId> 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<string> 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<SecureValue> 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<SecureFile> encrypt_secure_files(FileManager *file_manager, const secure_storage::Secret &master_secret,
vector<FileId> 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

149
td/telegram/SecureValue.h Normal file
View File

@ -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<telegram_api::SecureValueType> &&secure_value_type);
SecureValueType get_secure_value_type_td_api(tl_object_ptr<td_api::PassportDataType> &&passport_data_type);
vector<SecureValueType> get_secure_value_types(
vector<tl_object_ptr<telegram_api::SecureValueType>> &&secure_value_types);
td_api::object_ptr<td_api::PassportDataType> get_passport_data_type_object(SecureValueType type);
td_api::object_ptr<telegram_api::SecureValueType> get_secure_value_type_telegram_object(SecureValueType type);
vector<td_api::object_ptr<td_api::PassportDataType>> get_passport_data_types_object(
const vector<SecureValueType> &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<telegram_api::SecureFile> &&secure_file_ptr);
vector<SecureFile> get_secure_files(FileManager *file_manager,
vector<tl_object_ptr<telegram_api::SecureFile>> &&secure_files);
telegram_api::object_ptr<telegram_api::InputSecureFile> get_input_secure_file_object(FileManager *file_manager,
const SecureFile &file);
td_api::object_ptr<td_api::file> get_encrypted_file_object(FileManager *file_manager, const SecureFile &file);
vector<td_api::object_ptr<td_api::file>> get_encrypted_files_object(FileManager *file_manager,
const vector<SecureFile> &files);
vector<telegram_api::object_ptr<telegram_api::InputSecureFile>> get_input_secure_files_object(
FileManager *file_manager, const vector<SecureFile> &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<telegram_api::secureData> &&secure_data);
telegram_api::object_ptr<telegram_api::secureData> get_secure_data_object(const SecureData &data);
struct EncryptedSecureValue {
SecureValueType type = SecureValueType::None;
SecureData data;
vector<SecureFile> 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<telegram_api::secureValue> &&secure_value);
vector<EncryptedSecureValue> get_encrypted_secure_values(
FileManager *file_manager, vector<tl_object_ptr<telegram_api::secureValue>> &&secure_values);
td_api::object_ptr<td_api::encryptedPassportData> get_encrypted_passport_data_object(FileManager *file_manager,
const EncryptedSecureValue &value);
telegram_api::object_ptr<telegram_api::inputSecureValue> get_input_secure_value_object(
FileManager *file_manager, const EncryptedSecureValue &value);
vector<td_api::object_ptr<td_api::encryptedPassportData>> get_encrypted_passport_data_object(
FileManager *file_manager, const vector<EncryptedSecureValue> &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<telegram_api::secureCredentialsEncrypted> &&credentials);
td_api::object_ptr<td_api::encryptedCredentials> get_encrypted_credentials_object(const SecureCredentials &credentials);
class SecureValue {
public:
SecureValueType type;
string data;
vector<FileId> files;
};
Result<SecureValue> get_secure_value(td_api::object_ptr<td_api::inputPassportData> &&input_passport_data);
Result<FileId> decrypt_secure_file(FileManager *file_manager, const secure_storage::Secret &secret,
const SecureFile &secure_file);
Result<vector<FileId>> decrypt_secure_files(FileManager *file_manager, const secure_storage::Secret &secret,
const vector<SecureFile> &secure_file);
Result<string> decrypt_secure_data(const secure_storage::Secret &secret, const SecureData &secure_data);
Result<SecureValue> 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<SecureFile> encrypt_secure_files(FileManager *file_manager, const secure_storage::Secret &master_secret,
vector<FileId> 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

107
td/telegram/SecureValue.hpp Normal file
View File

@ -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 <class StorerT>
void store(SecureFile file, StorerT &storer) {
store(file.file_id, storer);
store(file.file_hash, storer);
store(file.encrypted_secret, storer);
}
template <class ParserT>
void parse(SecureFile &file, ParserT &parser) {
parse(file.file_id, parser);
parse(file.file_hash, parser);
parse(file.encrypted_secret, parser);
}
template <class StorerT>
void store(const SecureData &data, StorerT &storer) {
store(data.data, storer);
store(data.hash, storer);
store(data.encrypted_secret, storer);
}
template <class ParserT>
void parse(SecureData &data, ParserT &parser) {
parse(data.data, parser);
parse(data.hash, parser);
parse(data.encrypted_secret, parser);
}
template <class StorerT>
void store(const SecureCredentials &credentials, StorerT &storer) {
store(credentials.data, storer);
store(credentials.hash, storer);
store(credentials.encrypted_secret, storer);
}
template <class ParserT>
void parse(SecureCredentials &credentials, ParserT &parser) {
parse(credentials.data, parser);
parse(credentials.hash, parser);
parse(credentials.encrypted_secret, parser);
}
template <class StorerT>
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 <class ParserT>
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

View File

@ -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<telegram_api::InputSecureFile> 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<tl_object_ptr<secret_api::DocumentAttribute>> attributes;
@ -1347,7 +1351,7 @@ SecretInputMedia StickersManager::get_secret_input_media(FileId sticker_file_id,
make_tl_object<secret_api::documentAttributeImageSize>(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<secret_api::decryptedMessageMediaDocument>(
@ -1356,6 +1360,7 @@ SecretInputMedia StickersManager::get_secret_input_media(FileId sticker_file_id,
narrow_cast<int32>(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<int64> 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<std::tuple<FileId, bool, bool>> 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_ptr<td_api::In
auto file_id = r_file_id.move_as_ok();
auto file_view = td_->file_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_ptr<td_api::InputF
auto file_id = r_file_id.move_as_ok();
auto file_view = td_->file_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<FileId> StickersManager::get_attached_sticker_file_ids(const vector<int32
LOG(WARNING) << "Sticker " << file_id << " has no remote location";
continue;
}
if (file_view.remote_location().is_encrypted()) {
LOG(WARNING) << "Sticker " << file_id << " is encrypted";
continue;
}
if (file_view.remote_location().is_web()) {
LOG(WARNING) << "Sticker " << file_id << " is web";
continue;
}
if (!file_view.remote_location().is_document()) {
LOG(WARNING) << "Sticker " << file_id << " is encrypted";
continue;
}
result.push_back(file_id);
if (!td_->auth_manager_->is_bot()) {
@ -3594,7 +3598,7 @@ int32 StickersManager::get_recent_stickers_hash(const vector<FileId> &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<uint64>(file_view.remote_location().get_id());
numbers.push_back(static_cast<uint32>(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<SaveRecentStickerQuery>(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<Unit>
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_ptr<td_api::InputF
// 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<FaveStickerQuery>(std::move(promise))
->send(file_view.remote_location().as_input_document(), true);
@ -4140,7 +4144,7 @@ vector<string> StickersManager::get_sticker_emojis(const tl_object_ptr<td_api::I
promise.set_value(Unit());
return {};
}
if (file_view.remote_location().is_encrypted()) {
if (!file_view.remote_location().is_document()) {
promise.set_value(Unit());
return {};
}

View File

@ -45,6 +45,7 @@
#include "td/telegram/PasswordManager.h"
#include "td/telegram/Photo.h"
#include "td/telegram/PrivacyManager.h"
#include "td/telegram/SecureValue.h"
#include "td/telegram/SecretChatId.h"
#include "td/telegram/SecretChatsManager.h"
#include "td/telegram/StateManager.h"
@ -61,6 +62,7 @@
#include "td/telegram/td_api.hpp"
#include "td/telegram/telegram_api.h"
#include "td/telegram/telegram_api.hpp"
#include "td/actor/actor.h"
#include "td/actor/PromiseFuture.h"
@ -71,9 +73,11 @@
#include "td/utils/format.h"
#include "td/utils/MimeType.h"
#include "td/utils/misc.h"
#include "td/utils/optional.h"
#include "td/utils/PathView.h"
#include "td/utils/port/path.h"
#include "td/utils/Random.h"
#include "td/utils/overloaded.h"
#include "td/utils/Slice.h"
#include "td/utils/Status.h"
#include "td/utils/Timer.h"
@ -3796,6 +3800,134 @@ class GetTermsOfServiceRequest : public RequestActor<string> {
}
};
class GetSecureValue : public NetQueryCallback {
public:
GetSecureValue(std::string password, SecureValueType type, Promise<SecureValue> promise)
: password_(std::move(password)), type_(type), promise_(std::move(promise)) {
}
private:
string password_;
SecureValueType type_;
Promise<SecureValue> promise_;
optional<EncryptedSecureValue> encrypted_secure_value_;
optional<secure_storage::Secret> secret_;
void on_error(Status status) {
promise_.set_error(std::move(status));
stop();
}
void on_secret(Result<secure_storage::Secret> 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<telegram_api::object_ptr<telegram_api::SecureValueType>> 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<int64>(),
PromiseCreator::lambda([actor_id = actor_id(this)](Result<secure_storage::Secret> 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<telegram_api::account_getSecureValue>(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<Unit> promise)
: password_(std::move(password)), secure_value_(std::move(secure_value)), promise_(std::move(promise)) {
}
private:
string password_;
SecureValue secure_value_;
Promise<Unit> promise_;
optional<secure_storage::Secret> 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<secure_storage::Secret> 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<int64>(),
PromiseCreator::lambda([actor_id = actor_id(this)](Result<secure_storage::Secret> 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<telegram_api::account_saveSecureValue>(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<TdCallback> 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<telegram_api::InputSecureFile> 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>("DeviceTokenManager", create_reference());
hashtag_hints_ = create_actor<HashtagHints>("HashtagHints", "text", create_reference());
password_manager_ = create_actor<PasswordManager>("PasswordManager", create_reference());
G()->set_password_manager(password_manager_.get());
privacy_manager_ = create_actor<PrivacyManager>("PrivacyManager", create_reference());
secret_chats_manager_ = create_actor<SecretChatsManager>("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>("GetSecureValue", std::move(request.password_),
get_secure_value_type_td_api(std::move(request.type_)),
PromiseCreator::lambda([](Result<SecureValue> 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>(
"SetSecureValue", std::move(request.password_), r_secure_value.move_as_ok(),
PromiseCreator::lambda([](Result<Unit> 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();

View File

@ -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);

View File

@ -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<const telegram_api::messageActionChatCreate *>(action);

View File

@ -934,6 +934,35 @@ class CliClient final : public Actor {
return nullptr;
}
static tl_object_ptr<td_api::PassportDataType> as_passport_data_type(string passport_data_type) {
if (passport_data_type == "address" || passport_data_type == "a") {
return make_tl_object<td_api::passportDataTypeAddress>();
}
if (passport_data_type == "email" || passport_data_type == "e") {
return make_tl_object<td_api::passportDataTypeEmailAddress>();
}
if (passport_data_type == "phone" || passport_data_type == "p") {
return make_tl_object<td_api::passportDataTypePhoneNumber>();
}
return make_tl_object<td_api::passportDataTypePassport>();
}
static tl_object_ptr<td_api::inputPassportData> as_input_passport_data(string passport_data_type) {
return nullptr;
/* TODO
vector<td_api::object_ptr<td_api::InputFile>> files;
if (passport_data_type == "address" || passport_data_type == "a") {
return make_tl_object<td_api::inputPassportDataAddress>("cucumber lives here", std::move(files));
}
if (passport_data_type == "email" || passport_data_type == "e") {
return make_tl_object<td_api::inputPassportDataEmailAddress>("{todo}");
}
if (passport_data_type == "phone" || passport_data_type == "p") {
return make_tl_object<td_api::inputPassportDataPhoneNumber>("{todo}");
}
return make_tl_object<td_api::inputPassportDataIdentity>("I am cucumber", std::move(files));
*/
}
static td_api::object_ptr<td_api::Object> execute(tl_object_ptr<td_api::Function> 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<td_api::getTemporaryPasswordState>());
} else if (op == "ctp" || op == "CreateTemporaryPassword") {
send_request(make_tl_object<td_api::createTemporaryPassword>(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<td_api::getPassportData>(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<td_api::setPassportData>(as_input_passport_data(passport_data_type), password));
} else if (op == "pdu" || op == "processDcUpdate") {
string dc_id;
string ip_port;

View File

@ -18,6 +18,7 @@
#include "td/utils/ScopeGuard.h"
#include <tuple>
#include <utility>
namespace td {
void FileLoader::set_resource_manager(ActorShared<ResourceManager> 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();

View File

@ -141,7 +141,7 @@ Result<string> search_file(CSlice dir, CSlice name, int64 expected_size) {
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"};
"wallpapers", "video_notes", "passport_temp", "passport"};
string get_file_base_dir(const FileDirType &file_dir_type) {
switch (file_dir_type) {

View File

@ -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<td_api::FileType> as_td_api(FileType file_type) {
return make_tl_object<td_api::fileTypeWallpaper>();
case FileType::VideoNote:
return make_tl_object<td_api::fileTypeVideoNote>();
case FileType::Secure:
return make_tl_object<td_api::fileTypeSecure>();
case FileType::SecureRaw:
return make_tl_object<td_api::fileTypeSecureEncrypted>();
case FileType::None:
return make_tl_object<td_api::fileTypeNone>();
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<telegram_api::inputWebFileLocation> as_input_web_file_location() const {
CHECK(is_web());
@ -584,8 +610,10 @@ class FullRemoteFileLocation {
case LocationType::Photo:
return make_tl_object<telegram_api::inputFileLocation>(photo().volume_id_, photo().local_id_, photo().secret_);
case LocationType::Common:
if (is_encrypted()) {
if (is_encrypted_secret()) {
return make_tl_object<telegram_api::inputEncryptedFileLocation>(common().id_, common().access_hash_);
} else if (is_secure()) {
return make_tl_object<telegram_api::inputSecureFileLocation>(common().id_, common().access_hash_);
} else {
return make_tl_object<telegram_api::inputDocumentFileLocation>(common().id_, common().access_hash_, 0);
}
@ -599,7 +627,7 @@ class FullRemoteFileLocation {
tl_object_ptr<telegram_api::InputDocument> 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<telegram_api::inputDocument>(common().id_, common().access_hash_);
}
@ -609,9 +637,13 @@ class FullRemoteFileLocation {
}
tl_object_ptr<telegram_api::InputEncryptedFile> 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<telegram_api::inputEncryptedFile>(common().id_, common().access_hash_);
}
tl_object_ptr<telegram_api::InputSecureFile> as_input_secure_file() const {
CHECK(is_secure()) << "Can't call as_input_secure_file on a non-secure file";
return make_tl_object<telegram_api::inputSecureFile>(common().id_, common().access_hash_);
}
// TODO: this constructor is just for immediate unserialize
FullRemoteFileLocation() = default;

View File

@ -1887,6 +1887,12 @@ tl_object_ptr<td_api::file> FileManager::get_file_object(FileId file_id, bool wi
file_view.has_remote_location(), remote_size));
}
vector<tl_object_ptr<td_api::file>> FileManager::get_files_object(const vector<FileId> &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<FileId> FileManager::check_input_file_id(FileType type, Result<FileId> 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<telegram_api::InputEncryptedFile> input_file;
if (partial_remote.is_big_) {
input_file = make_tl_object<telegram_api::inputEncryptedFileBigUploaded>(
@ -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<telegram_api::InputSecureFile> input_file;
input_file = make_tl_object<telegram_api::inputSecureFileUploaded>(
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<telegram_api::InputFile> input_file;
if (partial_remote.is_big_) {

View File

@ -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<telegram_api::InputFile> input_file) = 0;
virtual void on_upload_encrypted_ok(FileId file_id, tl_object_ptr<telegram_api::InputEncryptedFile> input_file) = 0;
virtual void on_upload_secure_ok(FileId file_id, tl_object_ptr<telegram_api::InputSecureFile> 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<td_api::file> get_file_object(FileId file_id, bool with_main_file_id = true);
vector<tl_object_ptr<td_api::file>> get_files_object(const vector<FileId> &file_ids, bool with_main_file_id = true);
Result<FileId> get_input_thumbnail_file_id(const tl_object_ptr<td_api::InputFile> &thumb_input_file,
DialogId owner_dialog_id, bool is_encrypted) TD_WARN_UNUSED_RESULT;

View File

@ -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);

View File

@ -18,7 +18,7 @@ class HeaderStorer {
}
template <class StorerT>
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;

View File

@ -8,7 +8,6 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
namespace td {
namespace tl {

View File

@ -13,6 +13,7 @@
#include <openssl/rand.h>
#endif
#include <array>
#include <cstring>
#include <limits>
#include <random>

View File

@ -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 <openssl/aes.h>
@ -485,7 +486,6 @@ Result<BufferSlice> 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);

View File

@ -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"