set/get passport data
GitOrigin-RevId: 4fe8b44738ac91524a0d286db5d33d338b5b75e8
This commit is contained in:
parent
022bd092ce
commit
5e79712797
@ -131,6 +131,10 @@ class Secret {
|
|||||||
int64 get_hash() const;
|
int64 get_hash() const;
|
||||||
Secret clone() const;
|
Secret clone() const;
|
||||||
|
|
||||||
|
static constexpr size_t size() {
|
||||||
|
return sizeof(secret_.raw);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Secret(UInt256 secret, int64 hash);
|
Secret(UInt256 secret, int64 hash);
|
||||||
UInt256 secret_;
|
UInt256 secret_;
|
||||||
|
@ -9,8 +9,10 @@
|
|||||||
#include "td/telegram/files/FileManager.h"
|
#include "td/telegram/files/FileManager.h"
|
||||||
#include "td/telegram/td_api.h"
|
#include "td/telegram/td_api.h"
|
||||||
#include "td/telegram/telegram_api.h"
|
#include "td/telegram/telegram_api.h"
|
||||||
|
#include "td/telegram/telegram_api.hpp"
|
||||||
|
|
||||||
#include "td/utils/misc.h"
|
#include "td/utils/misc.h"
|
||||||
|
#include "td/utils/overloaded.h"
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
|
|
||||||
@ -161,10 +163,9 @@ SecureFile get_secure_file(FileManager *file_manager, tl_object_ptr<telegram_api
|
|||||||
LOG(ERROR) << "Wrong dc_id = " << dc_id;
|
LOG(ERROR) << "Wrong dc_id = " << dc_id;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
result.file_id =
|
result.file_id = file_manager->register_remote(
|
||||||
file_manager->register_remote(FullRemoteFileLocation(FileType::SecureRaw, secure_file->id_,
|
FullRemoteFileLocation(FileType::Secure, secure_file->id_, secure_file->access_hash_, DcId::internal(dc_id)),
|
||||||
secure_file->access_hash_, DcId::internal(dc_id)),
|
FileLocationSource::FromServer, {}, 0, 0, "");
|
||||||
FileLocationSource::FromServer, {}, 0, 0, "");
|
|
||||||
result.encrypted_secret = secure_file->secret_.as_slice().str();
|
result.encrypted_secret = secure_file->secret_.as_slice().str();
|
||||||
result.file_hash = secure_file->file_hash_.as_slice().str();
|
result.file_hash = secure_file->file_hash_.as_slice().str();
|
||||||
break;
|
break;
|
||||||
@ -189,13 +190,30 @@ vector<SecureFile> get_secure_files(FileManager *file_manager,
|
|||||||
}
|
}
|
||||||
|
|
||||||
telegram_api::object_ptr<telegram_api::InputSecureFile> get_input_secure_file_object(FileManager *file_manager,
|
telegram_api::object_ptr<telegram_api::InputSecureFile> get_input_secure_file_object(FileManager *file_manager,
|
||||||
const SecureFile &file) {
|
const SecureFile &file,
|
||||||
//TODO:
|
SecureInputFile &input_file) {
|
||||||
return nullptr;
|
CHECK(file_manager->get_file_view(file.file_id).file_id() ==
|
||||||
|
file_manager->get_file_view(input_file.file_id).file_id());
|
||||||
|
auto res = std::move(input_file.input_file);
|
||||||
|
if (res == nullptr) {
|
||||||
|
return file_manager->get_file_view(file.file_id).remote_location().as_input_secure_file();
|
||||||
|
}
|
||||||
|
telegram_api::downcast_call(*res, overloaded(
|
||||||
|
[&](telegram_api::inputSecureFileUploaded &uploaded) {
|
||||||
|
uploaded.secret_ = BufferSlice(file.encrypted_secret);
|
||||||
|
uploaded.file_hash_ = BufferSlice(file.file_hash);
|
||||||
|
},
|
||||||
|
[&](telegram_api::inputSecureFile &) { UNREACHABLE(); }));
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
td_api::object_ptr<td_api::file> get_encrypted_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) {
|
||||||
return file_manager->get_file_object(file.file_id);
|
auto file_view = file_manager->get_file_view(file.file_id);
|
||||||
|
auto file_id = file_manager->register_remote(
|
||||||
|
FullRemoteFileLocation(FileType::SecureRaw, file_view.remote_location().get_id(),
|
||||||
|
file_view.remote_location().get_access_hash(), file_view.remote_location().get_dc_id()),
|
||||||
|
FileLocationSource::FromServer, {}, 0, 0, "");
|
||||||
|
return file_manager->get_file_object(file_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<td_api::object_ptr<td_api::file>> get_encrypted_files_object(FileManager *file_manager,
|
vector<td_api::object_ptr<td_api::file>> get_encrypted_files_object(FileManager *file_manager,
|
||||||
@ -205,9 +223,15 @@ vector<td_api::object_ptr<td_api::file>> get_encrypted_files_object(FileManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
vector<telegram_api::object_ptr<telegram_api::InputSecureFile>> get_input_secure_files_object(
|
vector<telegram_api::object_ptr<telegram_api::InputSecureFile>> get_input_secure_files_object(
|
||||||
FileManager *file_manager, const vector<SecureFile> &file) {
|
FileManager *file_manager, const vector<SecureFile> &files, vector<SecureInputFile> &input_files) {
|
||||||
//TODO:
|
CHECK(files.size() == input_files.size());
|
||||||
return {};
|
vector<telegram_api::object_ptr<telegram_api::InputSecureFile>> res;
|
||||||
|
res.resize(files.size());
|
||||||
|
for (size_t i = 0; i < files.size(); i++) {
|
||||||
|
res[i] = get_input_secure_file_object(file_manager, files[i], input_files[i]);
|
||||||
|
}
|
||||||
|
LOG(ERROR) << res.size();
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const SecureData &lhs, const SecureData &rhs) {
|
bool operator==(const SecureData &lhs, const SecureData &rhs) {
|
||||||
@ -281,11 +305,12 @@ td_api::object_ptr<td_api::encryptedPassportData> get_encrypted_passport_data_ob
|
|||||||
bool is_plain = value.data.hash.empty();
|
bool is_plain = value.data.hash.empty();
|
||||||
return td_api::make_object<td_api::encryptedPassportData>(
|
return td_api::make_object<td_api::encryptedPassportData>(
|
||||||
get_passport_data_type_object(value.type), is_plain ? string() : value.data.data,
|
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(), get_encrypted_file_object(file_manager, value.selfie));
|
get_encrypted_files_object(file_manager, value.files), is_plain ? value.data.data : string(),
|
||||||
|
get_encrypted_file_object(file_manager, value.selfie));
|
||||||
}
|
}
|
||||||
|
|
||||||
telegram_api::object_ptr<telegram_api::inputSecureValue> get_input_secure_value_object(
|
telegram_api::object_ptr<telegram_api::inputSecureValue> get_input_secure_value_object(
|
||||||
FileManager *file_manager, const EncryptedSecureValue &value) {
|
FileManager *file_manager, const EncryptedSecureValue &value, std::vector<SecureInputFile> &input_files) {
|
||||||
bool is_plain = value.type == SecureValueType::PhoneNumber || value.type == SecureValueType::EmailAddress;
|
bool is_plain = value.type == SecureValueType::PhoneNumber || value.type == SecureValueType::EmailAddress;
|
||||||
bool has_selfie = value.selfie.file_id.is_valid();
|
bool has_selfie = value.selfie.file_id.is_valid();
|
||||||
int32 flags = 0;
|
int32 flags = 0;
|
||||||
@ -307,9 +332,9 @@ telegram_api::object_ptr<telegram_api::inputSecureValue> get_input_secure_value_
|
|||||||
flags |= telegram_api::inputSecureValue::SELFIE_MASK;
|
flags |= telegram_api::inputSecureValue::SELFIE_MASK;
|
||||||
}
|
}
|
||||||
return telegram_api::make_object<telegram_api::inputSecureValue>(
|
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),
|
flags, 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),
|
get_input_secure_files_object(file_manager, value.files, input_files), std::move(plain_data),
|
||||||
has_selfie ? get_input_secure_file_object(file_manager, value.selfie) : nullptr);
|
has_selfie ? /*TODO*/ nullptr : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<td_api::object_ptr<td_api::encryptedPassportData>> get_encrypted_passport_data_object(
|
vector<td_api::object_ptr<td_api::encryptedPassportData>> get_encrypted_passport_data_object(
|
||||||
@ -342,7 +367,8 @@ td_api::object_ptr<td_api::encryptedCredentials> get_encrypted_credentials_objec
|
|||||||
credentials.encrypted_secret);
|
credentials.encrypted_secret);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<SecureValue> get_secure_value(td_api::object_ptr<td_api::inputPassportData> &&input_passport_data) {
|
Result<SecureValue> get_secure_value(FileManager *file_manager,
|
||||||
|
td_api::object_ptr<td_api::inputPassportData> &&input_passport_data) {
|
||||||
if (input_passport_data == nullptr) {
|
if (input_passport_data == nullptr) {
|
||||||
return Status::Error(400, "InputPassportData must not be empty");
|
return Status::Error(400, "InputPassportData must not be empty");
|
||||||
}
|
}
|
||||||
@ -350,14 +376,31 @@ Result<SecureValue> get_secure_value(td_api::object_ptr<td_api::inputPassportDat
|
|||||||
SecureValue res;
|
SecureValue res;
|
||||||
res.type = get_secure_value_type_td_api(std::move(input_passport_data->type_));
|
res.type = get_secure_value_type_td_api(std::move(input_passport_data->type_));
|
||||||
res.data = std::move(input_passport_data->data_);
|
res.data = std::move(input_passport_data->data_);
|
||||||
// res.files = TODO
|
for (auto &file : input_passport_data->files_) {
|
||||||
|
TRY_RESULT(file_id, file_manager->get_input_file_id(FileType::Secure, std::move(file), DialogId{}, false, false,
|
||||||
|
false, true));
|
||||||
|
res.files.push_back(file_id);
|
||||||
|
}
|
||||||
// res.selfie = TODO
|
// res.selfie = TODO
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
td_api::object_ptr<td_api::passportData> get_passport_data_object(FileManager *file_manager, const SecureValue &value) {
|
||||||
|
std::vector<td_api::object_ptr<td_api::file>> files;
|
||||||
|
files = transform(value.files, [&](FileId id) { return file_manager->get_file_object(id, true); });
|
||||||
|
//TODO selfie
|
||||||
|
return td_api::make_object<td_api::passportData>(get_passport_data_type_object(value.type), value.data,
|
||||||
|
std::move(files), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
Result<FileId> decrypt_secure_file(FileManager *file_manager, const secure_storage::Secret &secret,
|
Result<FileId> decrypt_secure_file(FileManager *file_manager, const secure_storage::Secret &master_secret,
|
||||||
const SecureFile &secure_file) {
|
const SecureFile &secure_file) {
|
||||||
return Status::Error("TODO");
|
TRY_RESULT(hash, secure_storage::ValueHash::create(secure_file.file_hash));
|
||||||
|
TRY_RESULT(encrypted_secret, secure_storage::EncryptedSecret::create(secure_file.encrypted_secret));
|
||||||
|
TRY_RESULT(secret, encrypted_secret.decrypt(PSLICE() << master_secret.as_slice() << hash.as_slice()));
|
||||||
|
FileEncryptionKey key{secret};
|
||||||
|
key.set_value_hash(hash);
|
||||||
|
file_manager->set_encryption_key(secure_file.file_id, std::move(key));
|
||||||
|
return secure_file.file_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<vector<FileId>> decrypt_secure_files(FileManager *file_manager, const secure_storage::Secret &secret,
|
Result<vector<FileId>> decrypt_secure_files(FileManager *file_manager, const secure_storage::Secret &secret,
|
||||||
@ -391,9 +434,9 @@ Result<SecureValue> decrypt_encrypted_secure_value(FileManager *file_manager, co
|
|||||||
default: {
|
default: {
|
||||||
TRY_RESULT(data, decrypt_secure_data(secret, encrypted_secure_value.data));
|
TRY_RESULT(data, decrypt_secure_data(secret, encrypted_secure_value.data));
|
||||||
res.data = std::move(data);
|
res.data = std::move(data);
|
||||||
|
TRY_RESULT(files, decrypt_secure_files(file_manager, secret, encrypted_secure_value.files));
|
||||||
|
res.files = std::move(files);
|
||||||
// TODO
|
// TODO
|
||||||
//TRY_RESULT(files, decrypt_secure_files(file_manager, secret, encrypted_secure_value.files));
|
|
||||||
//res.files = std::move(files);
|
|
||||||
//TRY_RESULT(selfie, decrypt_secure_file(file_manager, secret, encrypted_secure_value.selfie));
|
//TRY_RESULT(selfie, decrypt_secure_file(file_manager, secret, encrypted_secure_value.selfie));
|
||||||
//res.selfie = std::move(selfie);
|
//res.selfie = std::move(selfie);
|
||||||
break;
|
break;
|
||||||
@ -404,8 +447,28 @@ Result<SecureValue> decrypt_encrypted_secure_value(FileManager *file_manager, co
|
|||||||
|
|
||||||
SecureFile encrypt_secure_file(FileManager *file_manager, const secure_storage::Secret &master_secret, FileId file,
|
SecureFile encrypt_secure_file(FileManager *file_manager, const secure_storage::Secret &master_secret, FileId file,
|
||||||
string &to_hash) {
|
string &to_hash) {
|
||||||
//TODO:
|
auto file_view = file_manager->get_file_view(file);
|
||||||
return SecureFile{};
|
if (file_view.empty()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (!file_view.encryption_key().is_secure()) {
|
||||||
|
LOG(ERROR) << "File has no encryption key";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (!file_view.encryption_key().has_value_hash()) {
|
||||||
|
LOG(ERROR) << "File has no hash";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
auto value_hash = file_view.encryption_key().value_hash();
|
||||||
|
auto secret = file_view.encryption_key().secret();
|
||||||
|
SecureFile res;
|
||||||
|
res.file_id = file;
|
||||||
|
res.file_hash = value_hash.as_slice().str();
|
||||||
|
res.encrypted_secret = secret.encrypt(PSLICE() << master_secret.as_slice() << value_hash.as_slice()).as_slice().str();
|
||||||
|
|
||||||
|
to_hash.append(res.file_hash);
|
||||||
|
to_hash.append(secret.as_slice().str());
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<SecureFile> encrypt_secure_files(FileManager *file_manager, const secure_storage::Secret &master_secret,
|
vector<SecureFile> encrypt_secure_files(FileManager *file_manager, const secure_storage::Secret &master_secret,
|
||||||
@ -442,8 +505,8 @@ EncryptedSecureValue encrypt_secure_value(FileManager *file_manager, const secur
|
|||||||
default: {
|
default: {
|
||||||
string to_hash;
|
string to_hash;
|
||||||
res.data = encrypt_secure_data(master_secret, secure_value.data, to_hash);
|
res.data = encrypt_secure_data(master_secret, secure_value.data, to_hash);
|
||||||
|
res.files = encrypt_secure_files(file_manager, master_secret, secure_value.files, to_hash);
|
||||||
// TODO
|
// TODO
|
||||||
//res.files = encrypt_secure_files(file_manager, master_secret, secure_value.files, to_hash);
|
|
||||||
//res.selfie = encrypt_secure_file(file_manager, master_secret, secure_value.selfie, to_hash);
|
//res.selfie = encrypt_secure_file(file_manager, master_secret, secure_value.selfie, to_hash);
|
||||||
res.hash = ss::calc_value_hash(to_hash).as_slice().str();
|
res.hash = ss::calc_value_hash(to_hash).as_slice().str();
|
||||||
break;
|
break;
|
||||||
|
@ -59,8 +59,13 @@ SecureFile get_secure_file(FileManager *file_manager, tl_object_ptr<telegram_api
|
|||||||
vector<SecureFile> get_secure_files(FileManager *file_manager,
|
vector<SecureFile> get_secure_files(FileManager *file_manager,
|
||||||
vector<tl_object_ptr<telegram_api::SecureFile>> &&secure_files);
|
vector<tl_object_ptr<telegram_api::SecureFile>> &&secure_files);
|
||||||
|
|
||||||
|
struct SecureInputFile {
|
||||||
|
FileId file_id;
|
||||||
|
tl_object_ptr<telegram_api::InputSecureFile> input_file;
|
||||||
|
};
|
||||||
telegram_api::object_ptr<telegram_api::InputSecureFile> get_input_secure_file_object(FileManager *file_manager,
|
telegram_api::object_ptr<telegram_api::InputSecureFile> get_input_secure_file_object(FileManager *file_manager,
|
||||||
const SecureFile &file);
|
const SecureFile &file,
|
||||||
|
SecureInputFile &input_file);
|
||||||
|
|
||||||
td_api::object_ptr<td_api::file> get_encrypted_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);
|
||||||
|
|
||||||
@ -68,7 +73,7 @@ vector<td_api::object_ptr<td_api::file>> get_encrypted_files_object(FileManager
|
|||||||
const vector<SecureFile> &files);
|
const vector<SecureFile> &files);
|
||||||
|
|
||||||
vector<telegram_api::object_ptr<telegram_api::InputSecureFile>> get_input_secure_files_object(
|
vector<telegram_api::object_ptr<telegram_api::InputSecureFile>> get_input_secure_files_object(
|
||||||
FileManager *file_manager, const vector<SecureFile> &file);
|
FileManager *file_manager, const vector<SecureFile> &file, vector<SecureInputFile> &input_files);
|
||||||
|
|
||||||
struct SecureData {
|
struct SecureData {
|
||||||
string data;
|
string data;
|
||||||
@ -103,7 +108,7 @@ vector<EncryptedSecureValue> get_encrypted_secure_values(
|
|||||||
td_api::object_ptr<td_api::encryptedPassportData> get_encrypted_passport_data_object(FileManager *file_manager,
|
td_api::object_ptr<td_api::encryptedPassportData> get_encrypted_passport_data_object(FileManager *file_manager,
|
||||||
const EncryptedSecureValue &value);
|
const EncryptedSecureValue &value);
|
||||||
telegram_api::object_ptr<telegram_api::inputSecureValue> get_input_secure_value_object(
|
telegram_api::object_ptr<telegram_api::inputSecureValue> get_input_secure_value_object(
|
||||||
FileManager *file_manager, const EncryptedSecureValue &value);
|
FileManager *file_manager, const EncryptedSecureValue &value, vector<SecureInputFile> &input_files);
|
||||||
|
|
||||||
vector<td_api::object_ptr<td_api::encryptedPassportData>> get_encrypted_passport_data_object(
|
vector<td_api::object_ptr<td_api::encryptedPassportData>> get_encrypted_passport_data_object(
|
||||||
FileManager *file_manager, const vector<EncryptedSecureValue> &values);
|
FileManager *file_manager, const vector<EncryptedSecureValue> &values);
|
||||||
@ -129,7 +134,10 @@ class SecureValue {
|
|||||||
FileId selfie;
|
FileId selfie;
|
||||||
};
|
};
|
||||||
|
|
||||||
Result<SecureValue> get_secure_value(td_api::object_ptr<td_api::inputPassportData> &&input_passport_data);
|
Result<SecureValue> get_secure_value(FileManager *file_manager,
|
||||||
|
td_api::object_ptr<td_api::inputPassportData> &&input_passport_data);
|
||||||
|
|
||||||
|
td_api::object_ptr<td_api::passportData> get_passport_data_object(FileManager *file_manager, const SecureValue &value);
|
||||||
|
|
||||||
Result<FileId> decrypt_secure_file(FileManager *file_manager, const secure_storage::Secret &secret,
|
Result<FileId> decrypt_secure_file(FileManager *file_manager, const secure_storage::Secret &secret,
|
||||||
const SecureFile &secure_file);
|
const SecureFile &secure_file);
|
||||||
|
@ -3800,16 +3800,17 @@ class GetTermsOfServiceRequest : public RequestActor<string> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using TdApiSecureValue = td_api::object_ptr<td_api::passportData>;
|
||||||
class GetSecureValue : public NetQueryCallback {
|
class GetSecureValue : public NetQueryCallback {
|
||||||
public:
|
public:
|
||||||
GetSecureValue(std::string password, SecureValueType type, Promise<SecureValue> promise)
|
GetSecureValue(std::string password, SecureValueType type, Promise<TdApiSecureValue> promise)
|
||||||
: password_(std::move(password)), type_(type), promise_(std::move(promise)) {
|
: password_(std::move(password)), type_(type), promise_(std::move(promise)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
string password_;
|
string password_;
|
||||||
SecureValueType type_;
|
SecureValueType type_;
|
||||||
Promise<SecureValue> promise_;
|
Promise<TdApiSecureValue> promise_;
|
||||||
optional<EncryptedSecureValue> encrypted_secure_value_;
|
optional<EncryptedSecureValue> encrypted_secure_value_;
|
||||||
optional<secure_storage::Secret> secret_;
|
optional<secure_storage::Secret> secret_;
|
||||||
|
|
||||||
@ -3832,8 +3833,12 @@ class GetSecureValue : public NetQueryCallback {
|
|||||||
if (!encrypted_secure_value_ || !secret_) {
|
if (!encrypted_secure_value_ || !secret_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
promise_.set_result(decrypt_encrypted_secure_value(G()->td().get_actor_unsafe()->file_manager_.get(), *secret_,
|
auto *file_manager = G()->td().get_actor_unsafe()->file_manager_.get();
|
||||||
*encrypted_secure_value_));
|
auto r_secure_value = decrypt_encrypted_secure_value(file_manager, *secret_, *encrypted_secure_value_);
|
||||||
|
if (r_secure_value.is_error()) {
|
||||||
|
return on_error(r_secure_value.move_as_error());
|
||||||
|
}
|
||||||
|
promise_.set_result(get_passport_data_object(file_manager, r_secure_value.move_as_ok()));
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
void start_up() override {
|
void start_up() override {
|
||||||
@ -3868,18 +3873,61 @@ class GetSecureValue : public NetQueryCallback {
|
|||||||
|
|
||||||
class SetSecureValue : public NetQueryCallback {
|
class SetSecureValue : public NetQueryCallback {
|
||||||
public:
|
public:
|
||||||
SetSecureValue(string password, SecureValue secure_value, Promise<Unit> promise)
|
SetSecureValue(string password, SecureValue secure_value, Promise<TdApiSecureValue> promise)
|
||||||
: password_(std::move(password)), secure_value_(std::move(secure_value)), promise_(std::move(promise)) {
|
: password_(std::move(password)), secure_value_(std::move(secure_value)), promise_(std::move(promise)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
string password_;
|
string password_;
|
||||||
SecureValue secure_value_;
|
SecureValue secure_value_;
|
||||||
Promise<Unit> promise_;
|
Promise<TdApiSecureValue> promise_;
|
||||||
optional<secure_storage::Secret> secret_;
|
optional<secure_storage::Secret> secret_;
|
||||||
|
|
||||||
|
size_t files_left_to_upload_ = 0;
|
||||||
|
vector<SecureInputFile> to_upload_;
|
||||||
|
class UploadCallback;
|
||||||
|
std::shared_ptr<UploadCallback> upload_callback_;
|
||||||
|
|
||||||
enum class State { WaitSecret, WaitSetValue } state_ = State::WaitSecret;
|
enum class State { WaitSecret, WaitSetValue } state_ = State::WaitSecret;
|
||||||
|
|
||||||
|
class UploadCallback : public FileManager::UploadCallback {
|
||||||
|
public:
|
||||||
|
explicit UploadCallback(ActorId<SetSecureValue> actor_id) : actor_id_(actor_id) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ActorId<SetSecureValue> actor_id_;
|
||||||
|
void on_upload_ok(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file) override {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
send_closure(actor_id_, &SetSecureValue::on_upload_ok, file_id, std::move(input_file));
|
||||||
|
}
|
||||||
|
void on_upload_error(FileId file_id, Status error) override {
|
||||||
|
send_closure(actor_id_, &SetSecureValue::on_upload_error, file_id, std::move(error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void on_upload_ok(FileId file_id, tl_object_ptr<telegram_api::InputSecureFile> input_file) {
|
||||||
|
for (auto &info : to_upload_) {
|
||||||
|
if (info.file_id != file_id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
CHECK(!info.input_file);
|
||||||
|
info.input_file = std::move(input_file);
|
||||||
|
CHECK(files_left_to_upload_ != 0);
|
||||||
|
files_left_to_upload_--;
|
||||||
|
return loop();
|
||||||
|
}
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
void on_upload_error(FileId file_id, Status error) {
|
||||||
|
return on_error(std::move(error));
|
||||||
|
}
|
||||||
|
|
||||||
void on_error(Status status) {
|
void on_error(Status status) {
|
||||||
promise_.set_error(std::move(status));
|
promise_.set_error(std::move(status));
|
||||||
stop();
|
stop();
|
||||||
@ -3900,6 +3948,31 @@ class SetSecureValue : public NetQueryCallback {
|
|||||||
PromiseCreator::lambda([actor_id = actor_id(this)](Result<secure_storage::Secret> r_secret) {
|
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);
|
send_closure(actor_id, &SetSecureValue::on_secret, std::move(r_secret), true);
|
||||||
}));
|
}));
|
||||||
|
auto *file_manager = G()->file_manager().get_actor_unsafe();
|
||||||
|
|
||||||
|
// Remove duplicated files
|
||||||
|
for (auto it = secure_value_.files.begin(); it != secure_value_.files.end();) {
|
||||||
|
bool is_duplicate = false;
|
||||||
|
for (auto pit = secure_value_.files.begin(); pit != it; pit++) {
|
||||||
|
if (file_manager->get_file_view(*it).file_id() == file_manager->get_file_view(*pit).file_id()) {
|
||||||
|
is_duplicate = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is_duplicate) {
|
||||||
|
it = secure_value_.files.erase(it);
|
||||||
|
} else {
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
to_upload_.resize(secure_value_.files.size());
|
||||||
|
upload_callback_ = std::make_shared<UploadCallback>(actor_id(this));
|
||||||
|
for (size_t i = 0; i < to_upload_.size(); i++) {
|
||||||
|
to_upload_[i].file_id = file_manager->dup_file_id(secure_value_.files[i]);
|
||||||
|
file_manager->upload(to_upload_[i].file_id, upload_callback_, 1, 0);
|
||||||
|
files_left_to_upload_++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() override {
|
void loop() override {
|
||||||
@ -3907,10 +3980,14 @@ class SetSecureValue : public NetQueryCallback {
|
|||||||
if (!secret_) {
|
if (!secret_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (files_left_to_upload_ != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto *file_manager = G()->td().get_actor_unsafe()->file_manager_.get();
|
auto *file_manager = G()->td().get_actor_unsafe()->file_manager_.get();
|
||||||
auto save_secure_value = telegram_api::account_saveSecureValue(
|
auto input_secure_value = get_input_secure_value_object(
|
||||||
get_input_secure_value_object(file_manager, encrypt_secure_value(file_manager, *secret_, secure_value_)),
|
file_manager, encrypt_secure_value(file_manager, *secret_, secure_value_), to_upload_);
|
||||||
secret_.value().get_hash());
|
auto save_secure_value =
|
||||||
|
telegram_api::account_saveSecureValue(std::move(input_secure_value), secret_.value().get_hash());
|
||||||
LOG(ERROR) << to_string(save_secure_value);
|
LOG(ERROR) << to_string(save_secure_value);
|
||||||
auto query = G()->net_query_creator().create(create_storer(save_secure_value));
|
auto query = G()->net_query_creator().create(create_storer(save_secure_value));
|
||||||
|
|
||||||
@ -3925,6 +4002,28 @@ class SetSecureValue : public NetQueryCallback {
|
|||||||
}
|
}
|
||||||
auto result = r_result.move_as_ok();
|
auto result = r_result.move_as_ok();
|
||||||
LOG(ERROR) << to_string(result);
|
LOG(ERROR) << to_string(result);
|
||||||
|
auto *file_manager = G()->td().get_actor_unsafe()->file_manager_.get();
|
||||||
|
auto encrypted_secure_value = get_encrypted_secure_value(file_manager, std::move(result));
|
||||||
|
if (secure_value_.files.size() != encrypted_secure_value.files.size()) {
|
||||||
|
return on_error(Status::Error("Different files count"));
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < secure_value_.files.size(); i++) {
|
||||||
|
auto file_view = file_manager->get_file_view(secure_value_.files[i]);
|
||||||
|
CHECK(!file_view.empty());
|
||||||
|
CHECK(file_view.encryption_key().has_value_hash());
|
||||||
|
if (file_view.encryption_key().value_hash().as_slice() != encrypted_secure_value.files[i].file_hash) {
|
||||||
|
LOG(ERROR) << "hash mismatch";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto status = file_manager->merge(encrypted_secure_value.files[i].file_id, secure_value_.files[i]);
|
||||||
|
LOG_IF(ERROR, status.is_error()) << status.error();
|
||||||
|
}
|
||||||
|
auto r_secure_value = decrypt_encrypted_secure_value(file_manager, *secret_, encrypted_secure_value);
|
||||||
|
if (r_secure_value.is_error()) {
|
||||||
|
return on_error(r_secure_value.move_as_error());
|
||||||
|
}
|
||||||
|
promise_.set_result(get_passport_data_object(file_manager, r_secure_value.move_as_ok()));
|
||||||
|
stop();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -6205,7 +6304,9 @@ void Td::on_request(uint64 id, td_api::uploadFile &request) {
|
|||||||
|
|
||||||
auto file_type = request.file_type_ == nullptr ? FileType::Temp : from_td_api(*request.file_type_);
|
auto file_type = request.file_type_ == nullptr ? FileType::Temp : from_td_api(*request.file_type_);
|
||||||
bool is_secret = file_type == FileType::Encrypted || file_type == FileType::EncryptedThumbnail;
|
bool is_secret = file_type == FileType::Encrypted || file_type == FileType::EncryptedThumbnail;
|
||||||
auto r_file_id = file_manager_->get_input_file_id(file_type, request.file_, DialogId(), false, is_secret, true);
|
bool is_secure = file_type == FileType::Secure;
|
||||||
|
auto r_file_id = file_manager_->get_input_file_id(file_type, request.file_, DialogId(), false, is_secret,
|
||||||
|
!is_secure && !is_secret, is_secure);
|
||||||
if (r_file_id.is_error()) {
|
if (r_file_id.is_error()) {
|
||||||
return send_error_raw(id, 400, r_file_id.error().message());
|
return send_error_raw(id, 400, r_file_id.error().message());
|
||||||
}
|
}
|
||||||
@ -6951,15 +7052,12 @@ void Td::on_request(uint64 id, td_api::getPassportData &request) {
|
|||||||
CHECK_AUTH();
|
CHECK_AUTH();
|
||||||
CHECK_IS_USER();
|
CHECK_IS_USER();
|
||||||
CLEAN_INPUT_STRING(request.password_);
|
CLEAN_INPUT_STRING(request.password_);
|
||||||
|
CREATE_REQUEST_PROMISE(promise);
|
||||||
if (request.type_ == nullptr) {
|
if (request.type_ == nullptr) {
|
||||||
return send_error_raw(id, 400, "Type must not be empty");
|
return promise.set_error(Status::Error(400, "Type must not be empty"));
|
||||||
}
|
}
|
||||||
create_actor<GetSecureValue>("GetSecureValue", std::move(request.password_),
|
create_actor<GetSecureValue>("GetSecureValue", std::move(request.password_),
|
||||||
get_secure_value_type_td_api(std::move(request.type_)),
|
get_secure_value_type_td_api(std::move(request.type_)), std::move(promise))
|
||||||
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();
|
.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6967,13 +7065,13 @@ void Td::on_request(uint64 id, td_api::setPassportData &request) {
|
|||||||
CHECK_AUTH();
|
CHECK_AUTH();
|
||||||
CHECK_IS_USER();
|
CHECK_IS_USER();
|
||||||
CLEAN_INPUT_STRING(request.password_);
|
CLEAN_INPUT_STRING(request.password_);
|
||||||
auto r_secure_value = get_secure_value(std::move(request.value_));
|
CREATE_REQUEST_PROMISE(promise);
|
||||||
|
auto r_secure_value = get_secure_value(file_manager_.get(), std::move(request.value_));
|
||||||
if (r_secure_value.is_error()) {
|
if (r_secure_value.is_error()) {
|
||||||
return send_closure(actor_id(this), &Td::send_error, id, r_secure_value.move_as_error());
|
return promise.set_error(r_secure_value.move_as_error());
|
||||||
}
|
}
|
||||||
create_actor<SetSecureValue>(
|
create_actor<SetSecureValue>("SetSecureValue", std::move(request.password_), r_secure_value.move_as_ok(),
|
||||||
"SetSecureValue", std::move(request.password_), r_secure_value.move_as_ok(),
|
std::move(promise))
|
||||||
PromiseCreator::lambda([](Result<Unit> result) { LOG_IF(ERROR, result.is_error()) << result.error(); }))
|
|
||||||
.release();
|
.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -946,21 +946,24 @@ class CliClient final : public Actor {
|
|||||||
}
|
}
|
||||||
return make_tl_object<td_api::passportDataTypePassport>();
|
return make_tl_object<td_api::passportDataTypePassport>();
|
||||||
}
|
}
|
||||||
static tl_object_ptr<td_api::inputPassportData> as_input_passport_data(string passport_data_type) {
|
static tl_object_ptr<td_api::inputPassportData> as_input_passport_data(string passport_data_type, string file) {
|
||||||
return nullptr;
|
|
||||||
/* TODO
|
|
||||||
vector<td_api::object_ptr<td_api::InputFile>> files;
|
vector<td_api::object_ptr<td_api::InputFile>> files;
|
||||||
|
LOG(ERROR) << "FILE " << file;
|
||||||
|
if (!file.empty()) {
|
||||||
|
files.push_back(make_tl_object<td_api::inputFileLocal>(file));
|
||||||
|
}
|
||||||
|
auto data_type = as_passport_data_type(passport_data_type);
|
||||||
|
string data;
|
||||||
if (passport_data_type == "address" || passport_data_type == "a") {
|
if (passport_data_type == "address" || passport_data_type == "a") {
|
||||||
return make_tl_object<td_api::inputPassportDataAddress>("cucumber lives here", std::move(files));
|
data = "cucumber lives here";
|
||||||
|
} else if (passport_data_type == "email" || passport_data_type == "e") {
|
||||||
|
data = "{todo}";
|
||||||
|
} else if (passport_data_type == "phone" || passport_data_type == "p") {
|
||||||
|
data = "{todo}";
|
||||||
|
} else {
|
||||||
|
data = "I am cucumber";
|
||||||
}
|
}
|
||||||
if (passport_data_type == "email" || passport_data_type == "e") {
|
return make_tl_object<td_api::inputPassportData>(std::move(data_type), std::move(data), std::move(files), nullptr);
|
||||||
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) {
|
static td_api::object_ptr<td_api::Object> execute(tl_object_ptr<td_api::Function> f) {
|
||||||
@ -1086,8 +1089,10 @@ class CliClient final : public Actor {
|
|||||||
} else if (op == "spd") {
|
} else if (op == "spd") {
|
||||||
string password;
|
string password;
|
||||||
string passport_data_type;
|
string passport_data_type;
|
||||||
std::tie(password, passport_data_type) = split(args);
|
string file;
|
||||||
send_request(make_tl_object<td_api::setPassportData>(as_input_passport_data(passport_data_type), password));
|
std::tie(password, args) = split(args);
|
||||||
|
std::tie(passport_data_type, file) = split(args);
|
||||||
|
send_request(make_tl_object<td_api::setPassportData>(as_input_passport_data(passport_data_type, file), password));
|
||||||
} else if (op == "pdu" || op == "processDcUpdate") {
|
} else if (op == "pdu" || op == "processDcUpdate") {
|
||||||
string dc_id;
|
string dc_id;
|
||||||
string ip_port;
|
string ip_port;
|
||||||
|
@ -36,7 +36,7 @@ FileDownloader::FileDownloader(const FullRemoteFileLocation &remote, const Local
|
|||||||
, callback_(std::move(callback))
|
, callback_(std::move(callback))
|
||||||
, is_small_(is_small)
|
, is_small_(is_small)
|
||||||
, search_file_(search_file) {
|
, search_file_(search_file) {
|
||||||
if (!encryption_key.empty()) {
|
if (!encryption_key.is_secret()) {
|
||||||
set_ordered_flag(true);
|
set_ordered_flag(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -48,6 +48,12 @@ Result<FileLoader::FileInfo> FileDownloader::init() {
|
|||||||
if (local_.type() == LocalFileLocation::Type::Full) {
|
if (local_.type() == LocalFileLocation::Type::Full) {
|
||||||
return Status::Error("File is already downloaded");
|
return Status::Error("File is already downloaded");
|
||||||
}
|
}
|
||||||
|
if (encryption_key_.is_secure() && !encryption_key_.has_value_hash()) {
|
||||||
|
LOG(ERROR) << "Can't download Secure file with unknown value_hash";
|
||||||
|
}
|
||||||
|
if (remote_.file_type_ == FileType::Secure) {
|
||||||
|
size_ = 0;
|
||||||
|
}
|
||||||
int ready_part_count = 0;
|
int ready_part_count = 0;
|
||||||
int32 part_size = 0;
|
int32 part_size = 0;
|
||||||
if (local_.type() == LocalFileLocation::Type::Partial) {
|
if (local_.type() == LocalFileLocation::Type::Partial) {
|
||||||
@ -56,7 +62,7 @@ Result<FileLoader::FileInfo> FileDownloader::init() {
|
|||||||
auto result_fd = FileFd::open(path_, FileFd::Write | FileFd::Read);
|
auto result_fd = FileFd::open(path_, FileFd::Write | FileFd::Read);
|
||||||
// TODO: check timestamps..
|
// TODO: check timestamps..
|
||||||
if (result_fd.is_ok()) {
|
if (result_fd.is_ok()) {
|
||||||
if (!encryption_key_.empty()) {
|
if (encryption_key_.is_secret()) {
|
||||||
CHECK(partial.iv_.size() == 32) << partial.iv_.size();
|
CHECK(partial.iv_.size() == 32) << partial.iv_.size();
|
||||||
encryption_key_.mutable_iv() = as<UInt256>(partial.iv_.data());
|
encryption_key_.mutable_iv() = as<UInt256>(partial.iv_.data());
|
||||||
next_part_ = partial.ready_part_count_;
|
next_part_ = partial.ready_part_count_;
|
||||||
@ -104,13 +110,22 @@ Status FileDownloader::on_ok(int64 size) {
|
|||||||
auto dir = get_files_dir(remote_.file_type_);
|
auto dir = get_files_dir(remote_.file_type_);
|
||||||
|
|
||||||
std::string path;
|
std::string path;
|
||||||
|
fd_.close();
|
||||||
|
if (encryption_key_.is_secure()) {
|
||||||
|
TRY_RESULT(file_path, open_temp_file(remote_.file_type_));
|
||||||
|
string tmp_path;
|
||||||
|
std::tie(std::ignore, tmp_path) = std::move(file_path);
|
||||||
|
TRY_STATUS(secure_storage::decrypt_file(encryption_key_.secret(), encryption_key_.value_hash(), path_, tmp_path));
|
||||||
|
path_ = std::move(tmp_path);
|
||||||
|
TRY_RESULT(path_stat, stat(path_));
|
||||||
|
size = path_stat.size_;
|
||||||
|
}
|
||||||
if (only_check_) {
|
if (only_check_) {
|
||||||
path = path_;
|
path = path_;
|
||||||
} else {
|
} else {
|
||||||
TRY_RESULT(perm_path, create_from_temp(path_, dir, name_));
|
TRY_RESULT(perm_path, create_from_temp(path_, dir, name_));
|
||||||
path = std::move(perm_path);
|
path = std::move(perm_path);
|
||||||
}
|
}
|
||||||
fd_.close();
|
|
||||||
callback_->on_ok(FullLocalFileLocation(remote_.file_type_, std::move(path), 0), size);
|
callback_->on_ok(FullLocalFileLocation(remote_.file_type_, std::move(path), 0), size);
|
||||||
return Status::OK();
|
return Status::OK();
|
||||||
}
|
}
|
||||||
@ -192,7 +207,7 @@ Result<bool> FileDownloader::should_restart_part(Part part, NetQueryPtr &net_que
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Result<std::pair<NetQueryPtr, bool>> FileDownloader::start_part(Part part, int32 part_count) {
|
Result<std::pair<NetQueryPtr, bool>> FileDownloader::start_part(Part part, int32 part_count) {
|
||||||
if (!encryption_key_.empty()) {
|
if (encryption_key_.is_secret()) {
|
||||||
part.size = (part.size + 15) & ~15; // fix for last part
|
part.size = (part.size + 15) & ~15; // fix for last part
|
||||||
}
|
}
|
||||||
// auto size = part.size;
|
// auto size = part.size;
|
||||||
@ -279,7 +294,7 @@ Result<size_t> FileDownloader::process_part(Part part, NetQueryPtr net_query) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto padded_size = part.size;
|
auto padded_size = part.size;
|
||||||
if (!encryption_key_.empty()) {
|
if (encryption_key_.is_secret()) {
|
||||||
padded_size = (part.size + 15) & ~15;
|
padded_size = (part.size + 15) & ~15;
|
||||||
}
|
}
|
||||||
LOG(INFO) << "Got " << bytes.size() << " padded_size=" << padded_size;
|
LOG(INFO) << "Got " << bytes.size() << " padded_size=" << padded_size;
|
||||||
@ -304,7 +319,7 @@ Result<size_t> FileDownloader::process_part(Part part, NetQueryPtr net_query) {
|
|||||||
ctr_state.init(key, iv);
|
ctr_state.init(key, iv);
|
||||||
ctr_state.decrypt(bytes.as_slice(), bytes.as_slice());
|
ctr_state.decrypt(bytes.as_slice(), bytes.as_slice());
|
||||||
}
|
}
|
||||||
if (!encryption_key_.empty()) {
|
if (encryption_key_.is_secret()) {
|
||||||
CHECK(next_part_ == part.id) << tag("expected part.id", next_part_) << "!=" << tag("part.id", part.id);
|
CHECK(next_part_ == part.id) << tag("expected part.id", next_part_) << "!=" << tag("part.id", part.id);
|
||||||
CHECK(!next_part_stop_);
|
CHECK(!next_part_stop_);
|
||||||
next_part_++;
|
next_part_++;
|
||||||
@ -332,10 +347,10 @@ void FileDownloader::on_progress(int32 part_count, int32 part_size, int32 ready_
|
|||||||
if (ready_size == 0 || path_.empty()) {
|
if (ready_size == 0 || path_.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (encryption_key_.empty()) {
|
if (encryption_key_.empty() || encryption_key_.is_secure()) {
|
||||||
callback_->on_partial_download(PartialLocalFileLocation{remote_.file_type_, path_, part_size, ready_part_count, ""},
|
callback_->on_partial_download(PartialLocalFileLocation{remote_.file_type_, path_, part_size, ready_part_count, ""},
|
||||||
ready_size);
|
ready_size);
|
||||||
} else {
|
} else if (encryption_key_.is_secret()) {
|
||||||
UInt256 iv;
|
UInt256 iv;
|
||||||
if (ready_part_count == next_part_) {
|
if (ready_part_count == next_part_) {
|
||||||
iv = encryption_key_.mutable_iv();
|
iv = encryption_key_.mutable_iv();
|
||||||
@ -345,6 +360,8 @@ void FileDownloader::on_progress(int32 part_count, int32 part_size, int32 ready_
|
|||||||
callback_->on_partial_download(PartialLocalFileLocation{remote_.file_type_, path_, part_size, ready_part_count,
|
callback_->on_partial_download(PartialLocalFileLocation{remote_.file_type_, path_, part_size, ready_part_count,
|
||||||
Slice(iv.raw, sizeof(iv)).str()},
|
Slice(iv.raw, sizeof(iv)).str()},
|
||||||
ready_size);
|
ready_size);
|
||||||
|
} else {
|
||||||
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,6 +181,17 @@ void FileLoadManager::on_partial_download(const PartialLocalFileLocation &partia
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FileLoadManager::on_hash(string hash) {
|
||||||
|
auto node_id = get_link_token();
|
||||||
|
auto node = nodes_container_.get(node_id);
|
||||||
|
if (node == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!stop_flag_) {
|
||||||
|
send_closure(callback_, &Callback::on_hash, node->query_id_, std::move(hash));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FileLoadManager::on_partial_upload(const PartialRemoteFileLocation &partial_remote, int64 ready_size) {
|
void FileLoadManager::on_partial_upload(const PartialRemoteFileLocation &partial_remote, int64 ready_size) {
|
||||||
auto node_id = get_link_token();
|
auto node_id = get_link_token();
|
||||||
auto node = nodes_container_.get(node_id);
|
auto node = nodes_container_.get(node_id);
|
||||||
|
@ -36,6 +36,7 @@ class FileLoadManager final : public Actor {
|
|||||||
virtual void on_start_download(QueryId id) = 0;
|
virtual void on_start_download(QueryId id) = 0;
|
||||||
virtual void on_partial_download(QueryId id, const PartialLocalFileLocation &partial_local, int64 ready_size) = 0;
|
virtual void on_partial_download(QueryId id, const PartialLocalFileLocation &partial_local, int64 ready_size) = 0;
|
||||||
virtual void on_partial_upload(QueryId id, const PartialRemoteFileLocation &partial_remote, int64 ready_size) = 0;
|
virtual void on_partial_upload(QueryId id, const PartialRemoteFileLocation &partial_remote, int64 ready_size) = 0;
|
||||||
|
virtual void on_hash(QueryId id, string hash) = 0;
|
||||||
virtual void on_upload_ok(QueryId id, FileType file_type, const PartialRemoteFileLocation &remtoe, int64 size) = 0;
|
virtual void on_upload_ok(QueryId id, FileType file_type, const PartialRemoteFileLocation &remtoe, int64 size) = 0;
|
||||||
virtual void on_upload_full_ok(QueryId id, const FullRemoteFileLocation &remote) = 0;
|
virtual void on_upload_full_ok(QueryId id, const FullRemoteFileLocation &remote) = 0;
|
||||||
virtual void on_download_ok(QueryId id, const FullLocalFileLocation &local, int64 size) = 0;
|
virtual void on_download_ok(QueryId id, const FullLocalFileLocation &local, int64 size) = 0;
|
||||||
@ -85,6 +86,7 @@ class FileLoadManager final : public Actor {
|
|||||||
void on_start_download();
|
void on_start_download();
|
||||||
void on_partial_download(const PartialLocalFileLocation &partial_local, int64 ready_size);
|
void on_partial_download(const PartialLocalFileLocation &partial_local, int64 ready_size);
|
||||||
void on_partial_upload(const PartialRemoteFileLocation &partial_remote, int64 ready_size);
|
void on_partial_upload(const PartialRemoteFileLocation &partial_remote, int64 ready_size);
|
||||||
|
void on_hash(string hash);
|
||||||
void on_ok_download(const FullLocalFileLocation &local, int64 size);
|
void on_ok_download(const FullLocalFileLocation &local, int64 size);
|
||||||
void on_ok_upload(FileType file_type, const PartialRemoteFileLocation &remote, int64 size);
|
void on_ok_upload(FileType file_type, const PartialRemoteFileLocation &remote, int64 size);
|
||||||
void on_ok_upload_full(const FullRemoteFileLocation &remote);
|
void on_ok_upload_full(const FullRemoteFileLocation &remote);
|
||||||
@ -121,6 +123,9 @@ class FileLoadManager final : public Actor {
|
|||||||
private:
|
private:
|
||||||
ActorShared<FileLoadManager> actor_id_;
|
ActorShared<FileLoadManager> actor_id_;
|
||||||
|
|
||||||
|
void on_hash(string hash) override {
|
||||||
|
send_closure(actor_id_, &FileLoadManager::on_hash, std::move(hash));
|
||||||
|
}
|
||||||
void on_partial_upload(const PartialRemoteFileLocation &partial_remote, int64 ready_size) override {
|
void on_partial_upload(const PartialRemoteFileLocation &partial_remote, int64 ready_size) override {
|
||||||
send_closure(actor_id_, &FileLoadManager::on_partial_upload, partial_remote, ready_size);
|
send_closure(actor_id_, &FileLoadManager::on_partial_upload, partial_remote, ready_size);
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "td/telegram/telegram_api.h"
|
#include "td/telegram/telegram_api.h"
|
||||||
|
|
||||||
#include "td/telegram/DialogId.h"
|
#include "td/telegram/DialogId.h"
|
||||||
|
#include "td/telegram/SecureStorage.h"
|
||||||
#include "td/telegram/net/DcId.h"
|
#include "td/telegram/net/DcId.h"
|
||||||
|
|
||||||
#include "td/utils/buffer.h"
|
#include "td/utils/buffer.h"
|
||||||
@ -157,42 +158,84 @@ constexpr int32 file_type_size = static_cast<int32>(FileType::Size);
|
|||||||
extern const char *file_type_name[file_type_size];
|
extern const char *file_type_name[file_type_size];
|
||||||
|
|
||||||
struct FileEncryptionKey {
|
struct FileEncryptionKey {
|
||||||
|
enum class Type { None, Secret, Secure };
|
||||||
FileEncryptionKey() = default;
|
FileEncryptionKey() = default;
|
||||||
FileEncryptionKey(Slice key, Slice iv) : key_iv_(key.size() + iv.size(), '\0') {
|
FileEncryptionKey(Slice key, Slice iv) : key_iv_(key.size() + iv.size(), '\0'), type_(Type::Secret) {
|
||||||
if (key.size() != 32 || iv.size() != 32) {
|
if (key.size() != 32 || iv.size() != 32) {
|
||||||
LOG(ERROR) << "Wrong key/iv sizes: " << key.size() << " " << iv.size();
|
LOG(ERROR) << "Wrong key/iv sizes: " << key.size() << " " << iv.size();
|
||||||
|
type_ = Type::None;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CHECK(key_iv_.size() == 64);
|
CHECK(key_iv_.size() == 64);
|
||||||
std::memcpy(&key_iv_[0], key.data(), key.size());
|
MutableSlice(key_iv_).copy_from(key);
|
||||||
std::memcpy(&key_iv_[key.size()], iv.data(), iv.size());
|
MutableSlice(key_iv_).remove_suffix(key.size()).copy_from(iv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileEncryptionKey(const secure_storage::Secret &secret) : type_(Type::Secure) {
|
||||||
|
key_iv_ = secret.as_slice().str();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_secret() const {
|
||||||
|
return type_ == Type::Secret;
|
||||||
|
}
|
||||||
|
bool is_secure() const {
|
||||||
|
return type_ == Type::Secure;
|
||||||
|
}
|
||||||
|
|
||||||
static FileEncryptionKey create() {
|
static FileEncryptionKey create() {
|
||||||
FileEncryptionKey res;
|
FileEncryptionKey res;
|
||||||
res.key_iv_.resize(64);
|
res.key_iv_.resize(64);
|
||||||
Random::secure_bytes(res.key_iv_);
|
Random::secure_bytes(res.key_iv_);
|
||||||
|
res.type_ = Type::Secret;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
static FileEncryptionKey create_secure_key() {
|
||||||
|
return FileEncryptionKey(secure_storage::Secret::create_new());
|
||||||
|
}
|
||||||
|
|
||||||
const UInt256 &key() const {
|
const UInt256 &key() const {
|
||||||
|
CHECK(is_secret());
|
||||||
CHECK(key_iv_.size() == 64);
|
CHECK(key_iv_.size() == 64);
|
||||||
return *reinterpret_cast<const UInt256 *>(key_iv_.data());
|
return *reinterpret_cast<const UInt256 *>(key_iv_.data());
|
||||||
}
|
}
|
||||||
Slice key_slice() const {
|
Slice key_slice() const {
|
||||||
|
CHECK(is_secret());
|
||||||
CHECK(key_iv_.size() == 64);
|
CHECK(key_iv_.size() == 64);
|
||||||
return Slice(key_iv_.data(), 32);
|
return Slice(key_iv_.data(), 32);
|
||||||
}
|
}
|
||||||
|
secure_storage::Secret secret() const {
|
||||||
|
CHECK(is_secure());
|
||||||
|
return secure_storage::Secret::create(Slice(key_iv_).truncate(32)).move_as_ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_value_hash() const {
|
||||||
|
CHECK(is_secure());
|
||||||
|
return key_iv_.size() > secure_storage::Secret::size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_value_hash(const secure_storage::ValueHash &value_hash) {
|
||||||
|
key_iv_.resize(secure_storage::Secret::size() + value_hash.as_slice().size());
|
||||||
|
MutableSlice(key_iv_).remove_prefix(secure_storage::Secret::size()).copy_from(value_hash.as_slice());
|
||||||
|
}
|
||||||
|
|
||||||
|
secure_storage::ValueHash value_hash() const {
|
||||||
|
CHECK(has_value_hash());
|
||||||
|
return secure_storage::ValueHash::create(Slice(key_iv_).remove_prefix(secure_storage::Secret::size())).move_as_ok();
|
||||||
|
}
|
||||||
|
|
||||||
UInt256 &mutable_iv() {
|
UInt256 &mutable_iv() {
|
||||||
|
CHECK(is_secret());
|
||||||
CHECK(key_iv_.size() == 64);
|
CHECK(key_iv_.size() == 64);
|
||||||
return *reinterpret_cast<UInt256 *>(&key_iv_[0] + 32);
|
return *reinterpret_cast<UInt256 *>(&key_iv_[0] + 32);
|
||||||
}
|
}
|
||||||
Slice iv_slice() const {
|
Slice iv_slice() const {
|
||||||
|
CHECK(is_secret());
|
||||||
CHECK(key_iv_.size() == 64);
|
CHECK(key_iv_.size() == 64);
|
||||||
return Slice(key_iv_.data() + 32, 32);
|
return Slice(key_iv_.data() + 32, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 calc_fingerprint() const {
|
int32 calc_fingerprint() const {
|
||||||
|
CHECK(is_secret());
|
||||||
char buf[16];
|
char buf[16];
|
||||||
md5(key_iv_, {buf, sizeof(buf)});
|
md5(key_iv_, {buf, sizeof(buf)});
|
||||||
return as<int32>(buf) ^ as<int32>(buf + 4);
|
return as<int32>(buf) ^ as<int32>(buf + 4);
|
||||||
@ -207,11 +250,17 @@ struct FileEncryptionKey {
|
|||||||
td::store(key_iv_, storer);
|
td::store(key_iv_, storer);
|
||||||
}
|
}
|
||||||
template <class ParserT>
|
template <class ParserT>
|
||||||
void parse(ParserT &parser) {
|
void parse(Type type, ParserT &parser) {
|
||||||
td::parse(key_iv_, parser);
|
td::parse(key_iv_, parser);
|
||||||
|
if (key_iv_.empty()) {
|
||||||
|
type_ = Type::None;
|
||||||
|
} else {
|
||||||
|
type_ = type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string key_iv_; // TODO wrong alignment is possible
|
string key_iv_; // TODO wrong alignment is possible
|
||||||
|
Type type_;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool operator==(const FileEncryptionKey &lhs, const FileEncryptionKey &rhs) {
|
inline bool operator==(const FileEncryptionKey &lhs, const FileEncryptionKey &rhs) {
|
||||||
@ -1141,9 +1190,11 @@ class FileData {
|
|||||||
using ::td::store;
|
using ::td::store;
|
||||||
bool has_owner_dialog_id = owner_dialog_id_.is_valid();
|
bool has_owner_dialog_id = owner_dialog_id_.is_valid();
|
||||||
bool has_expected_size = size_ == 0 && expected_size_ != 0;
|
bool has_expected_size = size_ == 0 && expected_size_ != 0;
|
||||||
|
bool encryption_key_is_secure = encryption_key_.is_secure();
|
||||||
BEGIN_STORE_FLAGS();
|
BEGIN_STORE_FLAGS();
|
||||||
STORE_FLAG(has_owner_dialog_id);
|
STORE_FLAG(has_owner_dialog_id);
|
||||||
STORE_FLAG(has_expected_size);
|
STORE_FLAG(has_expected_size);
|
||||||
|
STORE_FLAG(encryption_key_is_secure);
|
||||||
END_STORE_FLAGS();
|
END_STORE_FLAGS();
|
||||||
|
|
||||||
if (has_owner_dialog_id) {
|
if (has_owner_dialog_id) {
|
||||||
@ -1168,9 +1219,11 @@ class FileData {
|
|||||||
using ::td::parse;
|
using ::td::parse;
|
||||||
bool has_owner_dialog_id;
|
bool has_owner_dialog_id;
|
||||||
bool has_expected_size;
|
bool has_expected_size;
|
||||||
|
bool encryption_key_is_secure;
|
||||||
BEGIN_PARSE_FLAGS();
|
BEGIN_PARSE_FLAGS();
|
||||||
PARSE_FLAG(has_owner_dialog_id);
|
PARSE_FLAG(has_owner_dialog_id);
|
||||||
PARSE_FLAG(has_expected_size);
|
PARSE_FLAG(has_expected_size);
|
||||||
|
PARSE_FLAG(encryption_key_is_secure);
|
||||||
END_PARSE_FLAGS();
|
END_PARSE_FLAGS();
|
||||||
|
|
||||||
if (has_owner_dialog_id) {
|
if (has_owner_dialog_id) {
|
||||||
@ -1193,7 +1246,8 @@ class FileData {
|
|||||||
}
|
}
|
||||||
parse(remote_name_, parser);
|
parse(remote_name_, parser);
|
||||||
parse(url_, parser);
|
parse(url_, parser);
|
||||||
parse(encryption_key_, parser);
|
encryption_key_.parse(encryption_key_is_secure ? FileEncryptionKey::Type::Secure : FileEncryptionKey::Type::Secret,
|
||||||
|
parser);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
inline StringBuilder &operator<<(StringBuilder &sb, const FileData &file_data) {
|
inline StringBuilder &operator<<(StringBuilder &sb, const FileData &file_data) {
|
||||||
|
@ -300,8 +300,13 @@ int64 FileView::local_size() const {
|
|||||||
switch (node_->local_.type()) {
|
switch (node_->local_.type()) {
|
||||||
case LocalFileLocation::Type::Full:
|
case LocalFileLocation::Type::Full:
|
||||||
return node_->size_;
|
return node_->size_;
|
||||||
case LocalFileLocation::Type::Partial:
|
case LocalFileLocation::Type::Partial: {
|
||||||
|
if (is_encrypted_secure()) {
|
||||||
|
// File is not decrypted yet
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return node_->local_.partial().part_size_ * node_->local_.partial().ready_part_count_;
|
return node_->local_.partial().part_size_ * node_->local_.partial().ready_part_count_;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -509,6 +514,8 @@ string FileManager::get_file_name(FileType file_type, Slice path) {
|
|||||||
case FileType::Temp:
|
case FileType::Temp:
|
||||||
case FileType::EncryptedThumbnail:
|
case FileType::EncryptedThumbnail:
|
||||||
case FileType::Wallpaper:
|
case FileType::Wallpaper:
|
||||||
|
case FileType::Secure:
|
||||||
|
case FileType::SecureRaw:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
@ -1213,6 +1220,9 @@ void FileManager::flush_to_pmc(FileNodePtr node, bool new_remote, bool new_local
|
|||||||
data.local_ = LocalFileLocation();
|
data.local_ = LocalFileLocation();
|
||||||
data.remote_ = RemoteFileLocation();
|
data.remote_ = RemoteFileLocation();
|
||||||
}
|
}
|
||||||
|
if (data.remote_.type() != RemoteFileLocation::Type::Full && node->encryption_key_.is_secure()) {
|
||||||
|
data.remote_ = RemoteFileLocation();
|
||||||
|
}
|
||||||
|
|
||||||
data.size_ = node->size_;
|
data.size_ = node->size_;
|
||||||
data.expected_size_ = node->expected_size_;
|
data.expected_size_ = node->expected_size_;
|
||||||
@ -1670,6 +1680,10 @@ void FileManager::run_upload(FileNodePtr node, std::vector<int> bad_parts) {
|
|||||||
if (node->get_by_hash_ || node->generate_id_ == 0 || !node->generate_was_update_) {
|
if (node->get_by_hash_ || node->generate_id_ == 0 || !node->generate_was_update_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (file_view.has_generate_location() && file_view.generate_location().file_type_ == FileType::Secure) {
|
||||||
|
// Can't upload secure file before its size is known.
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
int8 priority = 0;
|
int8 priority = 0;
|
||||||
FileId file_id = node->main_file_id_;
|
FileId file_id = node->main_file_id_;
|
||||||
@ -1701,6 +1715,14 @@ void FileManager::run_upload(FileNodePtr node, std::vector<int> bad_parts) {
|
|||||||
LOG_IF(FATAL, !success) << "Failed to set encryption key for file " << file_id;
|
LOG_IF(FATAL, !success) << "Failed to set encryption key for file " << file_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create encryption key if necessary
|
||||||
|
if (file_view.has_local_location() && file_view.local_location().file_type_ == FileType::Secure &&
|
||||||
|
file_view.encryption_key().empty()) {
|
||||||
|
CHECK(!node->file_ids_.empty());
|
||||||
|
bool success = set_encryption_key(node->file_ids_[0], FileEncryptionKey::create_secure_key());
|
||||||
|
LOG_IF(FATAL, !success) << "Failed to set encryption key for file " << file_id;
|
||||||
|
}
|
||||||
|
|
||||||
if (old_priority != 0) {
|
if (old_priority != 0) {
|
||||||
LOG(INFO) << "File " << file_id << " is already uploading";
|
LOG(INFO) << "File " << file_id << " is already uploading";
|
||||||
CHECK(node->upload_id_ != 0);
|
CHECK(node->upload_id_ != 0);
|
||||||
@ -1894,7 +1916,7 @@ vector<tl_object_ptr<td_api::file>> FileManager::get_files_object(const vector<F
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result<FileId> FileManager::check_input_file_id(FileType type, Result<FileId> result, bool is_encrypted,
|
Result<FileId> FileManager::check_input_file_id(FileType type, Result<FileId> result, bool is_encrypted,
|
||||||
bool allow_zero) {
|
bool allow_zero, bool is_secure) {
|
||||||
TRY_RESULT(file_id, std::move(result));
|
TRY_RESULT(file_id, std::move(result));
|
||||||
if (allow_zero && !file_id.is_valid()) {
|
if (allow_zero && !file_id.is_valid()) {
|
||||||
return FileId();
|
return FileId();
|
||||||
@ -1906,7 +1928,7 @@ Result<FileId> FileManager::check_input_file_id(FileType type, Result<FileId> re
|
|||||||
}
|
}
|
||||||
auto file_view = FileView(file_node);
|
auto file_view = FileView(file_node);
|
||||||
FileType real_type = file_view.get_type();
|
FileType real_type = file_view.get_type();
|
||||||
if (!is_encrypted) {
|
if (!is_encrypted && !is_secure) {
|
||||||
if (real_type != type && !(real_type == FileType::Temp && file_view.has_url()) &&
|
if (real_type != type && !(real_type == FileType::Temp && file_view.has_url()) &&
|
||||||
!(is_document_type(real_type) && is_document_type(type))) {
|
!(is_document_type(real_type) && is_document_type(type))) {
|
||||||
// TODO: send encrypted file to unencrypted chat
|
// TODO: send encrypted file to unencrypted chat
|
||||||
@ -1953,7 +1975,7 @@ Result<FileId> FileManager::get_input_thumbnail_file_id(const tl_object_ptr<td_a
|
|||||||
|
|
||||||
Result<FileId> FileManager::get_input_file_id(FileType type, const tl_object_ptr<td_api::InputFile> &file,
|
Result<FileId> FileManager::get_input_file_id(FileType type, const tl_object_ptr<td_api::InputFile> &file,
|
||||||
DialogId owner_dialog_id, bool allow_zero, bool is_encrypted,
|
DialogId owner_dialog_id, bool allow_zero, bool is_encrypted,
|
||||||
bool get_by_hash) {
|
bool get_by_hash, bool is_secure) {
|
||||||
if (is_encrypted) {
|
if (is_encrypted) {
|
||||||
get_by_hash = false;
|
get_by_hash = false;
|
||||||
}
|
}
|
||||||
@ -1964,6 +1986,8 @@ Result<FileId> FileManager::get_input_file_id(FileType type, const tl_object_ptr
|
|||||||
return Status::Error(6, "InputFile not specified");
|
return Status::Error(6, "InputFile not specified");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto new_type = is_encrypted ? FileType::Encrypted : (is_secure ? FileType::Secure : type);
|
||||||
|
|
||||||
auto r_file_id = [&]() -> Result<FileId> {
|
auto r_file_id = [&]() -> Result<FileId> {
|
||||||
switch (file->get_id()) {
|
switch (file->get_id()) {
|
||||||
case td_api::inputFileLocal::ID: {
|
case td_api::inputFileLocal::ID: {
|
||||||
@ -1971,8 +1995,7 @@ Result<FileId> FileManager::get_input_file_id(FileType type, const tl_object_ptr
|
|||||||
if (allow_zero && path.empty()) {
|
if (allow_zero && path.empty()) {
|
||||||
return FileId();
|
return FileId();
|
||||||
}
|
}
|
||||||
return register_local(FullLocalFileLocation(is_encrypted ? FileType::Encrypted : type, path, 0),
|
return register_local(FullLocalFileLocation(new_type, path, 0), owner_dialog_id, 0, get_by_hash);
|
||||||
owner_dialog_id, 0, get_by_hash);
|
|
||||||
}
|
}
|
||||||
case td_api::inputFileId::ID: {
|
case td_api::inputFileId::ID: {
|
||||||
FileId file_id(static_cast<const td_api::inputFileId *>(file.get())->id_, 0);
|
FileId file_id(static_cast<const td_api::inputFileId *>(file.get())->id_, 0);
|
||||||
@ -1990,9 +2013,8 @@ Result<FileId> FileManager::get_input_file_id(FileType type, const tl_object_ptr
|
|||||||
}
|
}
|
||||||
case td_api::inputFileGenerated::ID: {
|
case td_api::inputFileGenerated::ID: {
|
||||||
auto *generated_file = static_cast<const td_api::inputFileGenerated *>(file.get());
|
auto *generated_file = static_cast<const td_api::inputFileGenerated *>(file.get());
|
||||||
return register_generate(is_encrypted ? FileType::Encrypted : type, FileLocationSource::FromUser,
|
return register_generate(new_type, FileLocationSource::FromUser, generated_file->original_path_,
|
||||||
generated_file->original_path_, generated_file->conversion_, owner_dialog_id,
|
generated_file->conversion_, owner_dialog_id, generated_file->expected_size_);
|
||||||
generated_file->expected_size_);
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
@ -2000,7 +2022,7 @@ Result<FileId> FileManager::get_input_file_id(FileType type, const tl_object_ptr
|
|||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
|
|
||||||
return check_input_file_id(type, std::move(r_file_id), is_encrypted, allow_zero);
|
return check_input_file_id(type, std::move(r_file_id), is_encrypted, allow_zero, is_secure);
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<tl_object_ptr<telegram_api::InputDocument>> FileManager::get_input_documents(const vector<FileId> &file_ids) {
|
vector<tl_object_ptr<telegram_api::InputDocument>> FileManager::get_input_documents(const vector<FileId> &file_ids) {
|
||||||
@ -2069,6 +2091,23 @@ void FileManager::on_partial_download(QueryId query_id, const PartialLocalFileLo
|
|||||||
try_flush_node(file_node);
|
try_flush_node(file_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FileManager::on_hash(QueryId query_id, string hash) {
|
||||||
|
auto query = queries_container_.get(query_id);
|
||||||
|
CHECK(query != nullptr);
|
||||||
|
|
||||||
|
auto file_id = query->file_id_;
|
||||||
|
|
||||||
|
auto file_node = get_file_node(file_id);
|
||||||
|
if (!file_node) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (file_node->upload_id_ != query_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_node->encryption_key_.set_value_hash(secure_storage::ValueHash::create(hash).move_as_ok());
|
||||||
|
}
|
||||||
|
|
||||||
void FileManager::on_partial_upload(QueryId query_id, const PartialRemoteFileLocation &partial_remote,
|
void FileManager::on_partial_upload(QueryId query_id, const PartialRemoteFileLocation &partial_remote,
|
||||||
int64 ready_size) {
|
int64 ready_size) {
|
||||||
auto query = queries_container_.get(query_id);
|
auto query = queries_container_.get(query_id);
|
||||||
|
@ -345,7 +345,7 @@ class FileManager : public FileLoadManager::Callback {
|
|||||||
DialogId owner_dialog_id, bool is_encrypted) TD_WARN_UNUSED_RESULT;
|
DialogId owner_dialog_id, bool is_encrypted) TD_WARN_UNUSED_RESULT;
|
||||||
Result<FileId> get_input_file_id(FileType type, const tl_object_ptr<td_api::InputFile> &file,
|
Result<FileId> get_input_file_id(FileType type, const tl_object_ptr<td_api::InputFile> &file,
|
||||||
DialogId owner_dialog_id, bool allow_zero, bool is_encrypted,
|
DialogId owner_dialog_id, bool allow_zero, bool is_encrypted,
|
||||||
bool get_by_hash = false) TD_WARN_UNUSED_RESULT;
|
bool get_by_hash = false, bool is_secure = false) TD_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
vector<tl_object_ptr<telegram_api::InputDocument>> get_input_documents(const vector<FileId> &file_ids);
|
vector<tl_object_ptr<telegram_api::InputDocument>> get_input_documents(const vector<FileId> &file_ids);
|
||||||
|
|
||||||
@ -356,8 +356,8 @@ class FileManager : public FileLoadManager::Callback {
|
|||||||
FileId parse_file(T &parser);
|
FileId parse_file(T &parser);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Result<FileId> check_input_file_id(FileType type, Result<FileId> result, bool is_encrypted,
|
Result<FileId> check_input_file_id(FileType type, Result<FileId> result, bool is_encrypted, bool allow_zero,
|
||||||
bool allow_zero) TD_WARN_UNUSED_RESULT;
|
bool is_secure) TD_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
FileId register_url(string url, FileType file_type, FileLocationSource file_location_source,
|
FileId register_url(string url, FileType file_type, FileLocationSource file_location_source,
|
||||||
DialogId owner_dialog_id);
|
DialogId owner_dialog_id);
|
||||||
@ -465,6 +465,7 @@ class FileManager : public FileLoadManager::Callback {
|
|||||||
|
|
||||||
void on_start_download(QueryId query_id) override;
|
void on_start_download(QueryId query_id) override;
|
||||||
void on_partial_download(QueryId query_id, const PartialLocalFileLocation &partial_local, int64 ready_size) override;
|
void on_partial_download(QueryId query_id, const PartialLocalFileLocation &partial_local, int64 ready_size) override;
|
||||||
|
void on_hash(QueryId query_id, string hash) override;
|
||||||
void on_partial_upload(QueryId query_id, const PartialRemoteFileLocation &partial_remote, int64 ready_size) override;
|
void on_partial_upload(QueryId query_id, const PartialRemoteFileLocation &partial_remote, int64 ready_size) override;
|
||||||
void on_download_ok(QueryId query_id, const FullLocalFileLocation &local, int64 size) override;
|
void on_download_ok(QueryId query_id, const FullLocalFileLocation &local, int64 size) override;
|
||||||
void on_upload_ok(QueryId query_id, FileType file_type, const PartialRemoteFileLocation &partial_remote,
|
void on_upload_ok(QueryId query_id, FileType file_type, const PartialRemoteFileLocation &partial_remote,
|
||||||
|
@ -39,11 +39,14 @@ void FileManager::store_file(FileId file_id, StorerT &storer, int32 ttl) const {
|
|||||||
bool has_encryption_key = false;
|
bool has_encryption_key = false;
|
||||||
bool has_expected_size =
|
bool has_expected_size =
|
||||||
file_store_type == FileStoreType::Remote && file_view.size() == 0 && file_view.expected_size() != 0;
|
file_store_type == FileStoreType::Remote && file_view.size() == 0 && file_view.expected_size() != 0;
|
||||||
|
bool has_secure_key = false;
|
||||||
if (file_store_type != FileStoreType::Empty) {
|
if (file_store_type != FileStoreType::Empty) {
|
||||||
has_encryption_key = !file_view.empty() && file_view.is_encrypted_secret();
|
has_encryption_key = !file_view.empty() && file_view.is_encrypted_secret();
|
||||||
|
has_secure_key = !file_view.empty() && file_view.is_encrypted_secure();
|
||||||
BEGIN_STORE_FLAGS();
|
BEGIN_STORE_FLAGS();
|
||||||
STORE_FLAG(has_encryption_key);
|
STORE_FLAG(has_encryption_key);
|
||||||
STORE_FLAG(has_expected_size);
|
STORE_FLAG(has_expected_size);
|
||||||
|
STORE_FLAG(has_secure_key);
|
||||||
END_STORE_FLAGS();
|
END_STORE_FLAGS();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,6 +102,8 @@ void FileManager::store_file(FileId file_id, StorerT &storer, int32 ttl) const {
|
|||||||
}
|
}
|
||||||
if (has_encryption_key) {
|
if (has_encryption_key) {
|
||||||
store(file_view.encryption_key(), storer);
|
store(file_view.encryption_key(), storer);
|
||||||
|
} else if (has_secure_key) {
|
||||||
|
store(file_view.encryption_key(), storer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,11 +118,13 @@ FileId FileManager::parse_file(ParserT &parser) {
|
|||||||
|
|
||||||
bool has_encryption_key = false;
|
bool has_encryption_key = false;
|
||||||
bool has_expected_size = false;
|
bool has_expected_size = false;
|
||||||
|
bool has_secure_key = false;
|
||||||
if (file_store_type != FileStoreType::Empty) {
|
if (file_store_type != FileStoreType::Empty) {
|
||||||
if (parser.version() >= static_cast<int32>(Version::StoreFileEncryptionKey)) {
|
if (parser.version() >= static_cast<int32>(Version::StoreFileEncryptionKey)) {
|
||||||
BEGIN_PARSE_FLAGS();
|
BEGIN_PARSE_FLAGS();
|
||||||
PARSE_FLAG(has_encryption_key);
|
PARSE_FLAG(has_encryption_key);
|
||||||
PARSE_FLAG(has_expected_size);
|
PARSE_FLAG(has_expected_size);
|
||||||
|
PARSE_FLAG(has_secure_key);
|
||||||
END_PARSE_FLAGS();
|
END_PARSE_FLAGS();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -212,7 +219,11 @@ FileId FileManager::parse_file(ParserT &parser) {
|
|||||||
|
|
||||||
if (has_encryption_key) {
|
if (has_encryption_key) {
|
||||||
FileEncryptionKey encryption_key;
|
FileEncryptionKey encryption_key;
|
||||||
parse(encryption_key, parser);
|
encryption_key.parse(FileEncryptionKey::Type::Secret, parser);
|
||||||
|
set_encryption_key(file_id, std::move(encryption_key));
|
||||||
|
} else if (has_secure_key) {
|
||||||
|
FileEncryptionKey encryption_key;
|
||||||
|
encryption_key.parse(FileEncryptionKey::Type::Secure, parser);
|
||||||
set_encryption_key(file_id, std::move(encryption_key));
|
set_encryption_key(file_id, std::move(encryption_key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
#include "td/telegram/telegram_api.h"
|
#include "td/telegram/telegram_api.h"
|
||||||
|
|
||||||
|
#include "td/telegram/files/FileLoaderUtils.h"
|
||||||
|
|
||||||
#include "td/telegram/Global.h"
|
#include "td/telegram/Global.h"
|
||||||
#include "td/telegram/net/NetQueryDispatcher.h"
|
#include "td/telegram/net/NetQueryDispatcher.h"
|
||||||
|
|
||||||
@ -16,6 +18,7 @@
|
|||||||
#include "td/utils/format.h"
|
#include "td/utils/format.h"
|
||||||
#include "td/utils/logging.h"
|
#include "td/utils/logging.h"
|
||||||
#include "td/utils/misc.h"
|
#include "td/utils/misc.h"
|
||||||
|
#include "td/utils/port/path.h"
|
||||||
#include "td/utils/Random.h"
|
#include "td/utils/Random.h"
|
||||||
#include "td/utils/ScopeGuard.h"
|
#include "td/utils/ScopeGuard.h"
|
||||||
|
|
||||||
@ -29,7 +32,7 @@ FileUploader::FileUploader(const LocalFileLocation &local, const RemoteFileLocat
|
|||||||
, encryption_key_(encryption_key)
|
, encryption_key_(encryption_key)
|
||||||
, bad_parts_(std::move(bad_parts))
|
, bad_parts_(std::move(bad_parts))
|
||||||
, callback_(std::move(callback)) {
|
, callback_(std::move(callback)) {
|
||||||
if (!encryption_key_.empty()) {
|
if (encryption_key_.is_secret()) {
|
||||||
iv_ = encryption_key_.mutable_iv();
|
iv_ = encryption_key_.mutable_iv();
|
||||||
generate_iv_ = encryption_key_.iv_slice().str();
|
generate_iv_ = encryption_key_.iv_slice().str();
|
||||||
}
|
}
|
||||||
@ -83,11 +86,17 @@ Result<FileLoader::PrefixInfo> FileUploader::on_update_local_location(const Loca
|
|||||||
SCOPE_EXIT {
|
SCOPE_EXIT {
|
||||||
try_release_fd();
|
try_release_fd();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (encryption_key_.is_secure() && !fd_path_.empty()) {
|
||||||
|
return Status::Error("Can't change local location for Secure file");
|
||||||
|
}
|
||||||
|
|
||||||
string path;
|
string path;
|
||||||
int64 local_size = 0;
|
int64 local_size = 0;
|
||||||
bool local_is_ready{false};
|
bool local_is_ready{false};
|
||||||
FileType file_type{FileType::Temp};
|
FileType file_type{FileType::Temp};
|
||||||
if (location.type() == LocalFileLocation::Type::Empty) {
|
if (location.type() == LocalFileLocation::Type::Empty ||
|
||||||
|
(location.type() == LocalFileLocation::Type::Partial && encryption_key_.is_secure())) {
|
||||||
path = "";
|
path = "";
|
||||||
local_size = 0;
|
local_size = 0;
|
||||||
local_is_ready = false;
|
local_is_ready = false;
|
||||||
@ -103,6 +112,18 @@ Result<FileLoader::PrefixInfo> FileUploader::on_update_local_location(const Loca
|
|||||||
file_type = location.full().file_type_;
|
file_type = location.full().file_type_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_temp = false;
|
||||||
|
if (encryption_key_.is_secure() && local_is_ready) {
|
||||||
|
TRY_RESULT(file_fd_path, open_temp_file(FileType::Temp));
|
||||||
|
file_fd_path.first.close();
|
||||||
|
auto new_path = std::move(file_fd_path.second);
|
||||||
|
TRY_RESULT(hash, secure_storage::encrypt_file(encryption_key_.secret(), path, new_path));
|
||||||
|
LOG(ERROR) << "ENCRYPT " << path << " " << new_path;
|
||||||
|
callback_->on_hash(hash.as_slice().str());
|
||||||
|
path = new_path;
|
||||||
|
is_temp = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!path.empty() && path != fd_path_) {
|
if (!path.empty() && path != fd_path_) {
|
||||||
auto res_fd = FileFd::open(path, FileFd::Read);
|
auto res_fd = FileFd::open(path, FileFd::Read);
|
||||||
|
|
||||||
@ -120,6 +141,7 @@ Result<FileLoader::PrefixInfo> FileUploader::on_update_local_location(const Loca
|
|||||||
fd_.close();
|
fd_.close();
|
||||||
fd_ = res_fd.move_as_ok();
|
fd_ = res_fd.move_as_ok();
|
||||||
fd_path_ = path;
|
fd_path_ = path;
|
||||||
|
is_temp_ = is_temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (local_is_ready) {
|
if (local_is_ready) {
|
||||||
@ -154,10 +176,18 @@ Result<FileLoader::PrefixInfo> FileUploader::on_update_local_location(const Loca
|
|||||||
|
|
||||||
Status FileUploader::on_ok(int64 size) {
|
Status FileUploader::on_ok(int64 size) {
|
||||||
fd_.close();
|
fd_.close();
|
||||||
|
if (is_temp_) {
|
||||||
|
LOG(ERROR) << "UNLINK " << fd_path_;
|
||||||
|
unlink(fd_path_).ignore();
|
||||||
|
}
|
||||||
return Status::OK();
|
return Status::OK();
|
||||||
}
|
}
|
||||||
void FileUploader::on_error(Status status) {
|
void FileUploader::on_error(Status status) {
|
||||||
fd_.close();
|
fd_.close();
|
||||||
|
if (is_temp_) {
|
||||||
|
LOG(ERROR) << "UNLINK " << fd_path_;
|
||||||
|
unlink(fd_path_).ignore();
|
||||||
|
}
|
||||||
callback_->on_error(std::move(status));
|
callback_->on_error(std::move(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,12 +226,12 @@ void FileUploader::after_start_parts() {
|
|||||||
|
|
||||||
Result<std::pair<NetQueryPtr, bool>> FileUploader::start_part(Part part, int32 part_count) {
|
Result<std::pair<NetQueryPtr, bool>> FileUploader::start_part(Part part, int32 part_count) {
|
||||||
auto padded_size = part.size;
|
auto padded_size = part.size;
|
||||||
if (!encryption_key_.empty()) {
|
if (encryption_key_.is_secret()) {
|
||||||
padded_size = (padded_size + 15) & ~15;
|
padded_size = (padded_size + 15) & ~15;
|
||||||
}
|
}
|
||||||
BufferSlice bytes(padded_size);
|
BufferSlice bytes(padded_size);
|
||||||
TRY_RESULT(size, fd_.pread(bytes.as_slice().truncate(part.size), part.offset));
|
TRY_RESULT(size, fd_.pread(bytes.as_slice().truncate(part.size), part.offset));
|
||||||
if (!encryption_key_.empty()) {
|
if (encryption_key_.is_secret()) {
|
||||||
Random::secure_bytes(bytes.as_slice().substr(part.size));
|
Random::secure_bytes(bytes.as_slice().substr(part.size));
|
||||||
if (next_offset_ == part.offset) {
|
if (next_offset_ == part.offset) {
|
||||||
aes_ige_encrypt(encryption_key_.key(), &iv_, bytes.as_slice(), bytes.as_slice());
|
aes_ige_encrypt(encryption_key_.key(), &iv_, bytes.as_slice(), bytes.as_slice());
|
||||||
|
@ -22,6 +22,7 @@ class FileUploader : public FileLoader {
|
|||||||
public:
|
public:
|
||||||
class Callback : public FileLoader::Callback {
|
class Callback : public FileLoader::Callback {
|
||||||
public:
|
public:
|
||||||
|
virtual void on_hash(string hash) = 0;
|
||||||
virtual void on_partial_upload(const PartialRemoteFileLocation &partial_remote, int64 ready_size) = 0;
|
virtual void on_partial_upload(const PartialRemoteFileLocation &partial_remote, int64 ready_size) = 0;
|
||||||
virtual void on_ok(FileType file_type, const PartialRemoteFileLocation &partial_remote, int64 size) = 0;
|
virtual void on_ok(FileType file_type, const PartialRemoteFileLocation &partial_remote, int64 size) = 0;
|
||||||
virtual void on_error(Status status) = 0;
|
virtual void on_error(Status status) = 0;
|
||||||
@ -52,6 +53,7 @@ class FileUploader : public FileLoader {
|
|||||||
|
|
||||||
FileFd fd_;
|
FileFd fd_;
|
||||||
string fd_path_;
|
string fd_path_;
|
||||||
|
bool is_temp_ = false;
|
||||||
int64 file_id_;
|
int64 file_id_;
|
||||||
bool big_flag_;
|
bool big_flag_;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user