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;
|
||||
Secret clone() const;
|
||||
|
||||
static constexpr size_t size() {
|
||||
return sizeof(secret_.raw);
|
||||
}
|
||||
|
||||
private:
|
||||
Secret(UInt256 secret, int64 hash);
|
||||
UInt256 secret_;
|
||||
|
@ -9,8 +9,10 @@
|
||||
#include "td/telegram/files/FileManager.h"
|
||||
#include "td/telegram/td_api.h"
|
||||
#include "td/telegram/telegram_api.h"
|
||||
#include "td/telegram/telegram_api.hpp"
|
||||
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/overloaded.h"
|
||||
|
||||
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;
|
||||
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.file_id = file_manager->register_remote(
|
||||
FullRemoteFileLocation(FileType::Secure, secure_file->id_, secure_file->access_hash_, DcId::internal(dc_id)),
|
||||
FileLocationSource::FromServer, {}, 0, 0, "");
|
||||
result.encrypted_secret = secure_file->secret_.as_slice().str();
|
||||
result.file_hash = secure_file->file_hash_.as_slice().str();
|
||||
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,
|
||||
const SecureFile &file) {
|
||||
//TODO:
|
||||
return nullptr;
|
||||
const SecureFile &file,
|
||||
SecureInputFile &input_file) {
|
||||
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) {
|
||||
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,
|
||||
@ -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(
|
||||
FileManager *file_manager, const vector<SecureFile> &file) {
|
||||
//TODO:
|
||||
return {};
|
||||
FileManager *file_manager, const vector<SecureFile> &files, vector<SecureInputFile> &input_files) {
|
||||
CHECK(files.size() == input_files.size());
|
||||
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) {
|
||||
@ -281,11 +305,12 @@ td_api::object_ptr<td_api::encryptedPassportData> get_encrypted_passport_data_ob
|
||||
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(), 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(
|
||||
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 has_selfie = value.selfie.file_id.is_valid();
|
||||
int32 flags = 0;
|
||||
@ -307,9 +332,9 @@ telegram_api::object_ptr<telegram_api::inputSecureValue> get_input_secure_value_
|
||||
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);
|
||||
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, input_files), std::move(plain_data),
|
||||
has_selfie ? /*TODO*/ nullptr : nullptr);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
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
|
||||
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
|
||||
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) {
|
||||
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,
|
||||
@ -391,9 +434,9 @@ Result<SecureValue> decrypt_encrypted_secure_value(FileManager *file_manager, co
|
||||
default: {
|
||||
TRY_RESULT(data, decrypt_secure_data(secret, encrypted_secure_value.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
|
||||
//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));
|
||||
//res.selfie = std::move(selfie);
|
||||
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,
|
||||
string &to_hash) {
|
||||
//TODO:
|
||||
return SecureFile{};
|
||||
auto file_view = file_manager->get_file_view(file);
|
||||
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,
|
||||
@ -442,8 +505,8 @@ EncryptedSecureValue encrypt_secure_value(FileManager *file_manager, const secur
|
||||
default: {
|
||||
string 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
|
||||
//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.hash = ss::calc_value_hash(to_hash).as_slice().str();
|
||||
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<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,
|
||||
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);
|
||||
|
||||
@ -68,7 +73,7 @@ vector<td_api::object_ptr<td_api::file>> get_encrypted_files_object(FileManager
|
||||
const vector<SecureFile> &files);
|
||||
|
||||
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 {
|
||||
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,
|
||||
const EncryptedSecureValue &value);
|
||||
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(
|
||||
FileManager *file_manager, const vector<EncryptedSecureValue> &values);
|
||||
@ -129,7 +134,10 @@ class SecureValue {
|
||||
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,
|
||||
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 {
|
||||
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)) {
|
||||
}
|
||||
|
||||
private:
|
||||
string password_;
|
||||
SecureValueType type_;
|
||||
Promise<SecureValue> promise_;
|
||||
Promise<TdApiSecureValue> promise_;
|
||||
optional<EncryptedSecureValue> encrypted_secure_value_;
|
||||
optional<secure_storage::Secret> secret_;
|
||||
|
||||
@ -3832,8 +3833,12 @@ class GetSecureValue : public NetQueryCallback {
|
||||
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_));
|
||||
auto *file_manager = G()->td().get_actor_unsafe()->file_manager_.get();
|
||||
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();
|
||||
}
|
||||
void start_up() override {
|
||||
@ -3868,18 +3873,61 @@ class GetSecureValue : public NetQueryCallback {
|
||||
|
||||
class SetSecureValue : public NetQueryCallback {
|
||||
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)) {
|
||||
}
|
||||
|
||||
private:
|
||||
string password_;
|
||||
SecureValue secure_value_;
|
||||
Promise<Unit> promise_;
|
||||
Promise<TdApiSecureValue> promise_;
|
||||
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;
|
||||
|
||||
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) {
|
||||
promise_.set_error(std::move(status));
|
||||
stop();
|
||||
@ -3900,6 +3948,31 @@ class SetSecureValue : public NetQueryCallback {
|
||||
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);
|
||||
}));
|
||||
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 {
|
||||
@ -3907,10 +3980,14 @@ class SetSecureValue : public NetQueryCallback {
|
||||
if (!secret_) {
|
||||
return;
|
||||
}
|
||||
if (files_left_to_upload_ != 0) {
|
||||
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());
|
||||
auto input_secure_value = get_input_secure_value_object(
|
||||
file_manager, encrypt_secure_value(file_manager, *secret_, secure_value_), to_upload_);
|
||||
auto save_secure_value =
|
||||
telegram_api::account_saveSecureValue(std::move(input_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));
|
||||
|
||||
@ -3925,6 +4002,28 @@ class SetSecureValue : public NetQueryCallback {
|
||||
}
|
||||
auto result = r_result.move_as_ok();
|
||||
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_);
|
||||
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()) {
|
||||
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_IS_USER();
|
||||
CLEAN_INPUT_STRING(request.password_);
|
||||
CREATE_REQUEST_PROMISE(promise);
|
||||
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_),
|
||||
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;
|
||||
}))
|
||||
get_secure_value_type_td_api(std::move(request.type_)), std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
@ -6967,13 +7065,13 @@ 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_));
|
||||
CREATE_REQUEST_PROMISE(promise);
|
||||
auto r_secure_value = get_secure_value(file_manager_.get(), 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());
|
||||
return promise.set_error(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(); }))
|
||||
create_actor<SetSecureValue>("SetSecureValue", std::move(request.password_), r_secure_value.move_as_ok(),
|
||||
std::move(promise))
|
||||
.release();
|
||||
}
|
||||
|
||||
|
@ -946,21 +946,24 @@ class CliClient final : public Actor {
|
||||
}
|
||||
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
|
||||
static tl_object_ptr<td_api::inputPassportData> as_input_passport_data(string passport_data_type, string file) {
|
||||
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") {
|
||||
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::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));
|
||||
*/
|
||||
return make_tl_object<td_api::inputPassportData>(std::move(data_type), std::move(data), std::move(files), nullptr);
|
||||
}
|
||||
|
||||
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") {
|
||||
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));
|
||||
string file;
|
||||
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") {
|
||||
string dc_id;
|
||||
string ip_port;
|
||||
|
@ -36,7 +36,7 @@ FileDownloader::FileDownloader(const FullRemoteFileLocation &remote, const Local
|
||||
, callback_(std::move(callback))
|
||||
, is_small_(is_small)
|
||||
, search_file_(search_file) {
|
||||
if (!encryption_key.empty()) {
|
||||
if (!encryption_key.is_secret()) {
|
||||
set_ordered_flag(true);
|
||||
}
|
||||
}
|
||||
@ -48,6 +48,12 @@ Result<FileLoader::FileInfo> FileDownloader::init() {
|
||||
if (local_.type() == LocalFileLocation::Type::Full) {
|
||||
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;
|
||||
int32 part_size = 0;
|
||||
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);
|
||||
// TODO: check timestamps..
|
||||
if (result_fd.is_ok()) {
|
||||
if (!encryption_key_.empty()) {
|
||||
if (encryption_key_.is_secret()) {
|
||||
CHECK(partial.iv_.size() == 32) << partial.iv_.size();
|
||||
encryption_key_.mutable_iv() = as<UInt256>(partial.iv_.data());
|
||||
next_part_ = partial.ready_part_count_;
|
||||
@ -104,13 +110,22 @@ Status FileDownloader::on_ok(int64 size) {
|
||||
auto dir = get_files_dir(remote_.file_type_);
|
||||
|
||||
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_) {
|
||||
path = path_;
|
||||
} else {
|
||||
TRY_RESULT(perm_path, create_from_temp(path_, dir, name_));
|
||||
path = std::move(perm_path);
|
||||
}
|
||||
fd_.close();
|
||||
callback_->on_ok(FullLocalFileLocation(remote_.file_type_, std::move(path), 0), size);
|
||||
return Status::OK();
|
||||
}
|
||||
@ -192,7 +207,7 @@ Result<bool> FileDownloader::should_restart_part(Part part, NetQueryPtr &net_que
|
||||
return false;
|
||||
}
|
||||
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
|
||||
}
|
||||
// auto size = part.size;
|
||||
@ -279,7 +294,7 @@ Result<size_t> FileDownloader::process_part(Part part, NetQueryPtr net_query) {
|
||||
}
|
||||
|
||||
auto padded_size = part.size;
|
||||
if (!encryption_key_.empty()) {
|
||||
if (encryption_key_.is_secret()) {
|
||||
padded_size = (part.size + 15) & ~15;
|
||||
}
|
||||
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.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_stop_);
|
||||
next_part_++;
|
||||
@ -332,10 +347,10 @@ void FileDownloader::on_progress(int32 part_count, int32 part_size, int32 ready_
|
||||
if (ready_size == 0 || path_.empty()) {
|
||||
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, ""},
|
||||
ready_size);
|
||||
} else {
|
||||
} else if (encryption_key_.is_secret()) {
|
||||
UInt256 iv;
|
||||
if (ready_part_count == next_part_) {
|
||||
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,
|
||||
Slice(iv.raw, sizeof(iv)).str()},
|
||||
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) {
|
||||
auto node_id = get_link_token();
|
||||
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_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_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_full_ok(QueryId id, const FullRemoteFileLocation &remote) = 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_partial_download(const PartialLocalFileLocation &partial_local, 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_upload(FileType file_type, const PartialRemoteFileLocation &remote, int64 size);
|
||||
void on_ok_upload_full(const FullRemoteFileLocation &remote);
|
||||
@ -121,6 +123,9 @@ class FileLoadManager final : public Actor {
|
||||
private:
|
||||
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 {
|
||||
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/DialogId.h"
|
||||
#include "td/telegram/SecureStorage.h"
|
||||
#include "td/telegram/net/DcId.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];
|
||||
|
||||
struct FileEncryptionKey {
|
||||
enum class Type { None, Secret, Secure };
|
||||
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) {
|
||||
LOG(ERROR) << "Wrong key/iv sizes: " << key.size() << " " << iv.size();
|
||||
type_ = Type::None;
|
||||
return;
|
||||
}
|
||||
CHECK(key_iv_.size() == 64);
|
||||
std::memcpy(&key_iv_[0], key.data(), key.size());
|
||||
std::memcpy(&key_iv_[key.size()], iv.data(), iv.size());
|
||||
MutableSlice(key_iv_).copy_from(key);
|
||||
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() {
|
||||
FileEncryptionKey res;
|
||||
res.key_iv_.resize(64);
|
||||
Random::secure_bytes(res.key_iv_);
|
||||
res.type_ = Type::Secret;
|
||||
return res;
|
||||
}
|
||||
static FileEncryptionKey create_secure_key() {
|
||||
return FileEncryptionKey(secure_storage::Secret::create_new());
|
||||
}
|
||||
|
||||
const UInt256 &key() const {
|
||||
CHECK(is_secret());
|
||||
CHECK(key_iv_.size() == 64);
|
||||
return *reinterpret_cast<const UInt256 *>(key_iv_.data());
|
||||
}
|
||||
Slice key_slice() const {
|
||||
CHECK(is_secret());
|
||||
CHECK(key_iv_.size() == 64);
|
||||
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() {
|
||||
CHECK(is_secret());
|
||||
CHECK(key_iv_.size() == 64);
|
||||
return *reinterpret_cast<UInt256 *>(&key_iv_[0] + 32);
|
||||
}
|
||||
Slice iv_slice() const {
|
||||
CHECK(is_secret());
|
||||
CHECK(key_iv_.size() == 64);
|
||||
return Slice(key_iv_.data() + 32, 32);
|
||||
}
|
||||
|
||||
int32 calc_fingerprint() const {
|
||||
CHECK(is_secret());
|
||||
char buf[16];
|
||||
md5(key_iv_, {buf, sizeof(buf)});
|
||||
return as<int32>(buf) ^ as<int32>(buf + 4);
|
||||
@ -207,11 +250,17 @@ struct FileEncryptionKey {
|
||||
td::store(key_iv_, storer);
|
||||
}
|
||||
template <class ParserT>
|
||||
void parse(ParserT &parser) {
|
||||
void parse(Type type, ParserT &parser) {
|
||||
td::parse(key_iv_, parser);
|
||||
if (key_iv_.empty()) {
|
||||
type_ = Type::None;
|
||||
} else {
|
||||
type_ = type;
|
||||
}
|
||||
}
|
||||
|
||||
string key_iv_; // TODO wrong alignment is possible
|
||||
Type type_;
|
||||
};
|
||||
|
||||
inline bool operator==(const FileEncryptionKey &lhs, const FileEncryptionKey &rhs) {
|
||||
@ -1141,9 +1190,11 @@ class FileData {
|
||||
using ::td::store;
|
||||
bool has_owner_dialog_id = owner_dialog_id_.is_valid();
|
||||
bool has_expected_size = size_ == 0 && expected_size_ != 0;
|
||||
bool encryption_key_is_secure = encryption_key_.is_secure();
|
||||
BEGIN_STORE_FLAGS();
|
||||
STORE_FLAG(has_owner_dialog_id);
|
||||
STORE_FLAG(has_expected_size);
|
||||
STORE_FLAG(encryption_key_is_secure);
|
||||
END_STORE_FLAGS();
|
||||
|
||||
if (has_owner_dialog_id) {
|
||||
@ -1168,9 +1219,11 @@ class FileData {
|
||||
using ::td::parse;
|
||||
bool has_owner_dialog_id;
|
||||
bool has_expected_size;
|
||||
bool encryption_key_is_secure;
|
||||
BEGIN_PARSE_FLAGS();
|
||||
PARSE_FLAG(has_owner_dialog_id);
|
||||
PARSE_FLAG(has_expected_size);
|
||||
PARSE_FLAG(encryption_key_is_secure);
|
||||
END_PARSE_FLAGS();
|
||||
|
||||
if (has_owner_dialog_id) {
|
||||
@ -1193,7 +1246,8 @@ class FileData {
|
||||
}
|
||||
parse(remote_name_, 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) {
|
||||
|
@ -300,8 +300,13 @@ int64 FileView::local_size() const {
|
||||
switch (node_->local_.type()) {
|
||||
case LocalFileLocation::Type::Full:
|
||||
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_;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -509,6 +514,8 @@ string FileManager::get_file_name(FileType file_type, Slice path) {
|
||||
case FileType::Temp:
|
||||
case FileType::EncryptedThumbnail:
|
||||
case FileType::Wallpaper:
|
||||
case FileType::Secure:
|
||||
case FileType::SecureRaw:
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@ -1213,6 +1220,9 @@ void FileManager::flush_to_pmc(FileNodePtr node, bool new_remote, bool new_local
|
||||
data.local_ = LocalFileLocation();
|
||||
data.remote_ = RemoteFileLocation();
|
||||
}
|
||||
if (data.remote_.type() != RemoteFileLocation::Type::Full && node->encryption_key_.is_secure()) {
|
||||
data.remote_ = RemoteFileLocation();
|
||||
}
|
||||
|
||||
data.size_ = node->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_) {
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
LOG(INFO) << "File " << file_id << " is already uploading";
|
||||
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,
|
||||
bool allow_zero) {
|
||||
bool allow_zero, bool is_secure) {
|
||||
TRY_RESULT(file_id, std::move(result));
|
||||
if (allow_zero && !file_id.is_valid()) {
|
||||
return FileId();
|
||||
@ -1906,7 +1928,7 @@ Result<FileId> FileManager::check_input_file_id(FileType type, Result<FileId> re
|
||||
}
|
||||
auto file_view = FileView(file_node);
|
||||
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()) &&
|
||||
!(is_document_type(real_type) && is_document_type(type))) {
|
||||
// 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,
|
||||
DialogId owner_dialog_id, bool allow_zero, bool is_encrypted,
|
||||
bool get_by_hash) {
|
||||
bool get_by_hash, bool is_secure) {
|
||||
if (is_encrypted) {
|
||||
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");
|
||||
}
|
||||
|
||||
auto new_type = is_encrypted ? FileType::Encrypted : (is_secure ? FileType::Secure : type);
|
||||
|
||||
auto r_file_id = [&]() -> Result<FileId> {
|
||||
switch (file->get_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()) {
|
||||
return FileId();
|
||||
}
|
||||
return register_local(FullLocalFileLocation(is_encrypted ? FileType::Encrypted : type, path, 0),
|
||||
owner_dialog_id, 0, get_by_hash);
|
||||
return register_local(FullLocalFileLocation(new_type, path, 0), owner_dialog_id, 0, get_by_hash);
|
||||
}
|
||||
case td_api::inputFileId::ID: {
|
||||
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: {
|
||||
auto *generated_file = static_cast<const td_api::inputFileGenerated *>(file.get());
|
||||
return register_generate(is_encrypted ? FileType::Encrypted : type, FileLocationSource::FromUser,
|
||||
generated_file->original_path_, generated_file->conversion_, owner_dialog_id,
|
||||
generated_file->expected_size_);
|
||||
return register_generate(new_type, FileLocationSource::FromUser, generated_file->original_path_,
|
||||
generated_file->conversion_, owner_dialog_id, generated_file->expected_size_);
|
||||
}
|
||||
default:
|
||||
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) {
|
||||
@ -2069,6 +2091,23 @@ void FileManager::on_partial_download(QueryId query_id, const PartialLocalFileLo
|
||||
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,
|
||||
int64 ready_size) {
|
||||
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;
|
||||
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,
|
||||
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);
|
||||
|
||||
@ -356,8 +356,8 @@ class FileManager : public FileLoadManager::Callback {
|
||||
FileId parse_file(T &parser);
|
||||
|
||||
private:
|
||||
Result<FileId> check_input_file_id(FileType type, Result<FileId> result, bool is_encrypted,
|
||||
bool allow_zero) TD_WARN_UNUSED_RESULT;
|
||||
Result<FileId> check_input_file_id(FileType type, Result<FileId> result, bool is_encrypted, bool allow_zero,
|
||||
bool is_secure) TD_WARN_UNUSED_RESULT;
|
||||
|
||||
FileId register_url(string url, FileType file_type, FileLocationSource file_location_source,
|
||||
DialogId owner_dialog_id);
|
||||
@ -465,6 +465,7 @@ class FileManager : public FileLoadManager::Callback {
|
||||
|
||||
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_hash(QueryId query_id, string hash) 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_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_expected_size =
|
||||
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) {
|
||||
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();
|
||||
STORE_FLAG(has_encryption_key);
|
||||
STORE_FLAG(has_expected_size);
|
||||
STORE_FLAG(has_secure_key);
|
||||
END_STORE_FLAGS();
|
||||
}
|
||||
|
||||
@ -99,6 +102,8 @@ void FileManager::store_file(FileId file_id, StorerT &storer, int32 ttl) const {
|
||||
}
|
||||
if (has_encryption_key) {
|
||||
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_expected_size = false;
|
||||
bool has_secure_key = false;
|
||||
if (file_store_type != FileStoreType::Empty) {
|
||||
if (parser.version() >= static_cast<int32>(Version::StoreFileEncryptionKey)) {
|
||||
BEGIN_PARSE_FLAGS();
|
||||
PARSE_FLAG(has_encryption_key);
|
||||
PARSE_FLAG(has_expected_size);
|
||||
PARSE_FLAG(has_secure_key);
|
||||
END_PARSE_FLAGS();
|
||||
}
|
||||
}
|
||||
@ -212,7 +219,11 @@ FileId FileManager::parse_file(ParserT &parser) {
|
||||
|
||||
if (has_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));
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,8 @@
|
||||
|
||||
#include "td/telegram/telegram_api.h"
|
||||
|
||||
#include "td/telegram/files/FileLoaderUtils.h"
|
||||
|
||||
#include "td/telegram/Global.h"
|
||||
#include "td/telegram/net/NetQueryDispatcher.h"
|
||||
|
||||
@ -16,6 +18,7 @@
|
||||
#include "td/utils/format.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/port/path.h"
|
||||
#include "td/utils/Random.h"
|
||||
#include "td/utils/ScopeGuard.h"
|
||||
|
||||
@ -29,7 +32,7 @@ FileUploader::FileUploader(const LocalFileLocation &local, const RemoteFileLocat
|
||||
, encryption_key_(encryption_key)
|
||||
, bad_parts_(std::move(bad_parts))
|
||||
, callback_(std::move(callback)) {
|
||||
if (!encryption_key_.empty()) {
|
||||
if (encryption_key_.is_secret()) {
|
||||
iv_ = encryption_key_.mutable_iv();
|
||||
generate_iv_ = encryption_key_.iv_slice().str();
|
||||
}
|
||||
@ -83,11 +86,17 @@ Result<FileLoader::PrefixInfo> FileUploader::on_update_local_location(const Loca
|
||||
SCOPE_EXIT {
|
||||
try_release_fd();
|
||||
};
|
||||
|
||||
if (encryption_key_.is_secure() && !fd_path_.empty()) {
|
||||
return Status::Error("Can't change local location for Secure file");
|
||||
}
|
||||
|
||||
string path;
|
||||
int64 local_size = 0;
|
||||
bool local_is_ready{false};
|
||||
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 = "";
|
||||
local_size = 0;
|
||||
local_is_ready = false;
|
||||
@ -103,6 +112,18 @@ Result<FileLoader::PrefixInfo> FileUploader::on_update_local_location(const Loca
|
||||
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_) {
|
||||
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_ = res_fd.move_as_ok();
|
||||
fd_path_ = path;
|
||||
is_temp_ = is_temp;
|
||||
}
|
||||
|
||||
if (local_is_ready) {
|
||||
@ -154,10 +176,18 @@ Result<FileLoader::PrefixInfo> FileUploader::on_update_local_location(const Loca
|
||||
|
||||
Status FileUploader::on_ok(int64 size) {
|
||||
fd_.close();
|
||||
if (is_temp_) {
|
||||
LOG(ERROR) << "UNLINK " << fd_path_;
|
||||
unlink(fd_path_).ignore();
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
void FileUploader::on_error(Status status) {
|
||||
fd_.close();
|
||||
if (is_temp_) {
|
||||
LOG(ERROR) << "UNLINK " << fd_path_;
|
||||
unlink(fd_path_).ignore();
|
||||
}
|
||||
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) {
|
||||
auto padded_size = part.size;
|
||||
if (!encryption_key_.empty()) {
|
||||
if (encryption_key_.is_secret()) {
|
||||
padded_size = (padded_size + 15) & ~15;
|
||||
}
|
||||
BufferSlice bytes(padded_size);
|
||||
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));
|
||||
if (next_offset_ == part.offset) {
|
||||
aes_ige_encrypt(encryption_key_.key(), &iv_, bytes.as_slice(), bytes.as_slice());
|
||||
|
@ -22,6 +22,7 @@ class FileUploader : public FileLoader {
|
||||
public:
|
||||
class Callback : public FileLoader::Callback {
|
||||
public:
|
||||
virtual void on_hash(string hash) = 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_error(Status status) = 0;
|
||||
@ -52,6 +53,7 @@ class FileUploader : public FileLoader {
|
||||
|
||||
FileFd fd_;
|
||||
string fd_path_;
|
||||
bool is_temp_ = false;
|
||||
int64 file_id_;
|
||||
bool big_flag_;
|
||||
|
||||
|
Reference in New Issue
Block a user