diff --git a/src/jamidht/accountarchive.cpp b/src/jamidht/accountarchive.cpp index 83082f1b14b4086d7842c4a75e4b46475d775b6a..0c23719a463c48872c9670294818a790436fe589 100644 --- a/src/jamidht/accountarchive.cpp +++ b/src/jamidht/accountarchive.cpp @@ -78,6 +78,10 @@ AccountArchive::deserialize(const std::vector<uint8_t>& dat) } catch (const std::exception& ex) { JAMI_ERR("Can't parse JSON: %s", ex.what()); } + + if (not id.first) { + throw std::runtime_error("Archive doesn't include account private key"); + } } std::string diff --git a/src/jamidht/archive_account_manager.cpp b/src/jamidht/archive_account_manager.cpp index de90098f202ae38e2a43bee342e5e4b5db42c139..1418e9b6107d1c66d0034078d1d99dede1a0e932 100644 --- a/src/jamidht/archive_account_manager.cpp +++ b/src/jamidht/archive_account_manager.cpp @@ -68,10 +68,24 @@ ArchiveAccountManager::initAuthentication( auto& this_ = *static_cast<ArchiveAccountManager*>(&accountManager); try { if (ctx->credentials->scheme == "file") { - this_.loadFromFile(ctx); - return; + // Import from external archive + this_.loadFromFile(*ctx); } else { - if (ctx->credentials->updateIdentity.first and ctx->credentials->updateIdentity.second) { + // Create/migrate local account + bool hasArchive = not ctx->credentials->uri.empty() + and fileutils::isFile(ctx->credentials->uri); + if (hasArchive) { + // Create/migrate from local archive + if (ctx->credentials->updateIdentity.first and + ctx->credentials->updateIdentity.second and + needsMigration(ctx->credentials->updateIdentity)) + { + this_.migrateAccount(*ctx); + } else { + this_.loadFromFile(*ctx); + } + } + else if (ctx->credentials->updateIdentity.first and ctx->credentials->updateIdentity.second) { auto future_keypair = dht::ThreadPool::computation().get<dev::KeyPair>(&dev::KeyPair::create); AccountArchive a; JAMI_WARN("[Auth] converting certificate from old account %s", ctx->credentials->updateIdentity.first->getPublicKey().getId().toString().c_str()); @@ -80,11 +94,10 @@ ArchiveAccountManager::initAuthentication( a.ca_key = std::make_shared<dht::crypto::PrivateKey>(fileutils::loadFile("ca.key", this_.path_)); } catch (...) {} this_.updateCertificates(a, ctx->credentials->updateIdentity); - auto keypair = future_keypair.get(); - a.eth_key = keypair.secret().makeInsecure().asBytes(); + a.eth_key = future_keypair.get().secret().makeInsecure().asBytes(); this_.onArchiveLoaded(*ctx, std::move(a)); } else { - this_.createAccount(ctx); + this_.createAccount(*ctx); } } } catch (const std::exception& e) { @@ -137,7 +150,7 @@ ArchiveAccountManager::updateCertificates(AccountArchive& archive, dht::crypto:: } void -ArchiveAccountManager::createAccount(const std::shared_ptr<AuthContext>& ctx) +ArchiveAccountManager::createAccount(AuthContext& ctx) { AccountArchive a; auto future_keypair = dht::ThreadPool::computation().get<dev::KeyPair>(&dev::KeyPair::create); @@ -155,21 +168,22 @@ ArchiveAccountManager::createAccount(const std::shared_ptr<AuthContext>& ctx) a.ca_key = ca.first; auto keypair = future_keypair.get(); a.eth_key = keypair.secret().makeInsecure().asBytes(); - onArchiveLoaded(*ctx, std::move(a)); + onArchiveLoaded(ctx, std::move(a)); } void -ArchiveAccountManager::loadFromFile(const std::shared_ptr<AuthContext>& ctx) +ArchiveAccountManager::loadFromFile(AuthContext& ctx) { + JAMI_WARN("[Auth] loading archive from: %s", ctx.credentials->uri.c_str()); AccountArchive archive; try { - archive = AccountArchive(ctx->credentials->uri, ctx->credentials->password); + archive = AccountArchive(ctx.credentials->uri, ctx.credentials->password); } catch (const std::exception& ex) { JAMI_WARN("[Auth] can't read file: %s", ex.what()); - ctx->onFailure(AuthError::UNKNOWN, ex.what()); + ctx.onFailure(AuthError::INVALID_ARGUMENTS, ex.what()); return; } - onArchiveLoaded(*ctx, std::move(archive)); + onArchiveLoaded(ctx, std::move(archive)); } struct ArchiveAccountManager::DhtLoadContext { @@ -259,6 +273,25 @@ ArchiveAccountManager::loadFromDHT(const std::shared_ptr<AuthContext>& ctx) dht::ThreadPool::computation().run(std::bind(search, false)); } +void +ArchiveAccountManager::migrateAccount(AuthContext& ctx) +{ + JAMI_WARN("[Auth] account migration needed"); + AccountArchive archive; + try { + archive = readArchive(ctx.credentials->password); + } catch (...) { + JAMI_DBG("[Auth] Can't load archive"); + ctx.onFailure(AuthError::INVALID_ARGUMENTS, ""); + return; + } + + if (updateCertificates(archive, ctx.credentials->updateIdentity)) { + onArchiveLoaded(ctx, std::move(archive)); + } else + ctx.onFailure(AuthError::UNKNOWN, ""); +} + void ArchiveAccountManager::onArchiveLoaded( AuthContext& ctx, @@ -273,7 +306,7 @@ ArchiveAccountManager::onArchiveLoaded( if (not a.id.second->isCA()) { JAMI_ERR("[Auth] trying to sign a certificate with a non-CA."); } - JAMI_WARN("generating device certificate"); + JAMI_WARN("[Auth] creating new device certificate"); auto request = ctx.request.get(); if (not request->verify()) { diff --git a/src/jamidht/archive_account_manager.h b/src/jamidht/archive_account_manager.h index c6c103f4a3ab46ed6d94f394e6308e09d67a8368..5a63aba8dec5d2655a9bf42a8e56e32cef6c750c 100644 --- a/src/jamidht/archive_account_manager.h +++ b/src/jamidht/archive_account_manager.h @@ -37,7 +37,6 @@ public: {}; struct ArchiveAccountCredentials : AccountCredentials { - std::string archivePath; in_port_t dhtPort; std::vector<std::string> dhtBootstrap; dht::crypto::Identity updateIdentity; @@ -73,14 +72,15 @@ private: struct DhtLoadContext; struct AuthContext { CertRequest request; - //std::unique_ptr<dht::crypto::CertificateRequest> request; std::unique_ptr<ArchiveAccountCredentials> credentials; std::unique_ptr<DhtLoadContext> dhtContext; AuthSuccessCallback onSuccess; AuthFailureCallback onFailure; }; - void createAccount(const std::shared_ptr<AuthContext>& ctx); + void createAccount(AuthContext& ctx); + void migrateAccount(AuthContext& ctx); + std::pair<std::string, std::shared_ptr<dht::Value>> makeReceipt(const dht::crypto::Identity& id, const dht::crypto::Certificate& device, const std::string& ethAccount); void updateArchive(AccountArchive& content/*, const ContactList& syncData*/) const; void saveArchive(AccountArchive& content, const std::string& pwd); @@ -89,7 +89,7 @@ private: bool updateCertificates(AccountArchive& archive, dht::crypto::Identity& device); static bool needsMigration(const dht::crypto::Identity& id); - void loadFromFile(const std::shared_ptr<AuthContext>& ctx); + void loadFromFile(AuthContext& ctx); void loadFromDHT(const std::shared_ptr<AuthContext>& ctx); void onArchiveLoaded(AuthContext& ctx, AccountArchive&& a); diff --git a/src/jamidht/jamiaccount.cpp b/src/jamidht/jamiaccount.cpp index aaffbf2c669ffceb971ed2e81e5cd6d8a5a268ef..2a41c7afa4a5a83692ff8267bd3ed8045a2dd861 100644 --- a/src/jamidht/jamiaccount.cpp +++ b/src/jamidht/jamiaccount.cpp @@ -904,9 +904,6 @@ JamiAccount::loadAccount(const std::string& archive_password, const std::string& } auto id = accountManager_->loadIdentity(tlsCertificateFile_, tlsPrivateKeyFile_, tlsPassword_); - /*bool hasArchive = not archivePath_.empty() - and fileutils::isFile(fileutils::getFullPath(idPath_, archivePath_));*/ - if (auto info = accountManager_->useIdentity(id, receipt_, receiptSignature_, std::move(callbacks))) { // normal loading path id_ = std::move(id); @@ -917,6 +914,13 @@ JamiAccount::loadAccount(const std::string& archive_password, const std::string& } } else if (isEnabled()) { + if (not managerUri_.empty() and archive_password.empty()) { + Migration::setState(accountID_, Migration::State::INVALID); + setRegistrationState(RegistrationState::ERROR_NEED_MIGRATION); + return; + } + + bool migrating = registrationState_ == RegistrationState::ERROR_NEED_MIGRATION; setRegistrationState(RegistrationState::INITIALIZING); auto fDeviceKey = dht::ThreadPool::computation().getShared<std::shared_ptr<dht::crypto::PrivateKey>>([](){ return std::make_shared<dht::crypto::PrivateKey>(dht::crypto::PrivateKey::generate()); @@ -937,16 +941,24 @@ JamiAccount::loadAccount(const std::string& archive_password, const std::string& if (archivePath_.empty()) { archivePath_ = "archive.gz"; } - acreds->archivePath = archivePath_; + auto archivePath = fileutils::getFullPath(idPath_, archivePath_); + bool hasArchive = fileutils::isFile(archivePath); if (not archive_path.empty()) { + // Importing external archive acreds->scheme = "file"; acreds->uri = archive_path; } else if (not archive_pin.empty()) { + // Importing from DHT acreds->scheme = "dht"; acreds->uri = archive_pin; acreds->dhtBootstrap = loadBootstrap(); acreds->dhtPort = (in_port_t)dhtPortUsed_; + } else if (hasArchive) { + // Migrating local account + acreds->scheme = "local"; + acreds->uri = std::move(archivePath); + acreds->updateIdentity = id; } creds = std::move(acreds); } else { @@ -960,12 +972,12 @@ JamiAccount::loadAccount(const std::string& archive_password, const std::string& accountManager_->initAuthentication( std::move(fReq), std::move(creds), - [this, fDeviceKey](const AccountInfo& info, + [this, fDeviceKey, migrating](const AccountInfo& info, const std::map<std::string, std::string>& config, std::string&& receipt, std::vector<uint8_t>&& receipt_signature) { - JAMI_WARN("Auth success !"); + JAMI_WARN("[Account %s] Auth success !", getAccountID().c_str()); fileutils::check_dir(idPath_.c_str(), 0700); @@ -994,16 +1006,25 @@ JamiAccount::loadAccount(const std::string& archive_password, const std::string& receipt_ = std::move(receipt); receiptSignature_ = std::move(receipt_signature); accountManager_->foundAccountDevice(info.identity.second, ringDeviceName_, clock::now()); + if (migrating) { + Migration::setState(getAccountID(), Migration::State::SUCCESS); + } setRegistrationState(RegistrationState::UNREGISTERED); saveConfig(); doRegister(); - }, [this](AccountManager::AuthError error, const std::string& message) - { - JAMI_WARN("Auth error: %d %s", (int)error, message.c_str()); - setRegistrationState(RegistrationState::ERROR_GENERIC); - runOnMainThread([id = getAccountID()] { - Manager::instance().removeAccount(id, true); - }); + }, [w = weak(), id = getAccountID()](AccountManager::AuthError error, const std::string& message) { + JAMI_WARN("[Account %s] Auth error: %d %s", id.c_str(), (int)error, message.c_str()); + if (error == AccountManager::AuthError::INVALID_ARGUMENTS) { + Migration::setState(id, Migration::State::INVALID); + if (auto acc = w.lock()) + acc->setRegistrationState(RegistrationState::ERROR_NEED_MIGRATION); + } else { + if (auto acc = w.lock()) + acc->setRegistrationState(RegistrationState::ERROR_GENERIC); + runOnMainThread([id = std::move(id)] { + Manager::instance().removeAccount(id, true); + }); + } }, std::move(callbacks)); } }