diff --git a/src/jamidht/archive_account_manager.cpp b/src/jamidht/archive_account_manager.cpp index 9e2fb54529b7b005fda9800f09e48dcfdbefe374..cbd033b3cc7c7affbcf6a9eac9e5209ff5459b60 100644 --- a/src/jamidht/archive_account_manager.cpp +++ b/src/jamidht/archive_account_manager.cpp @@ -40,6 +40,8 @@ namespace jami { const constexpr auto EXPORT_KEY_RENEWAL_TIME = std::chrono::minutes(20); constexpr auto AUTH_URI_SCHEME = "jami-auth://"sv; +constexpr auto CHANNEL_SCHEME = "auth:"sv; +constexpr auto OP_TIMEOUT = 5min; void ArchiveAccountManager::initAuthentication(PrivateKey key, @@ -73,8 +75,8 @@ ArchiveAccountManager::initAuthentication(PrivateKey key, return; } - dht::ThreadPool::computation().run([ctx = std::move(ctx), wthis = weak_from_this()] { - auto this_ = std::static_pointer_cast<ArchiveAccountManager>(wthis.lock()); + dht::ThreadPool::computation().run([ctx = std::move(ctx), wthis = weak()] { + auto this_ = wthis.lock(); if (not this_) return; try { @@ -315,16 +317,15 @@ toString(AuthDecodingState state) } } -struct ArchiveAccountManager::PayloadKey -{ - static constexpr auto passwordCorrect = "passwordCorrect"sv; - static constexpr auto canRetry = "canRetry"sv; - static constexpr auto archiveTransferredWithoutFailure = "archiveTransferredWithoutFailure"sv; - static constexpr auto accData = "accData"sv; - static constexpr auto authScheme = "authScheme"sv; - static constexpr auto password = "password"sv; - static constexpr auto stateMsg = "stateMsg"sv; -}; +namespace PayloadKey { +static constexpr auto passwordCorrect = "passwordCorrect"sv; +static constexpr auto canRetry = "canRetry"sv; +static constexpr auto archiveTransferredWithoutFailure = "archiveTransferredWithoutFailure"sv; +static constexpr auto accData = "accData"sv; +static constexpr auto authScheme = "authScheme"sv; +static constexpr auto password = "password"sv; +static constexpr auto stateMsg = "stateMsg"sv; +} struct ArchiveAccountManager::AuthMsg { @@ -332,8 +333,7 @@ struct ArchiveAccountManager::AuthMsg std::map<std::string, std::string> payload; MSGPACK_DEFINE_MAP(schemeId, payload) - void set(std::string_view key, std::string_view value) - { + void set(std::string_view key, std::string_view value) { payload.emplace(std::string(key), std::string(value)); } @@ -343,8 +343,7 @@ struct ArchiveAccountManager::AuthMsg void logMsg() { JAMI_DEBUG("[LinkDevice]\nLinkDevice::logMsg:\n{}", formatMsg()); } - std::string formatMsg() - { + std::string formatMsg() { std::string logStr = "=========\n"; logStr += fmt::format("scheme: {}\n", schemeId); for (const auto& [msgKey, msgVal] : payload) { @@ -353,6 +352,12 @@ struct ArchiveAccountManager::AuthMsg logStr += "========="; return logStr; } + + static AuthMsg timeout() { + AuthMsg timeoutMsg; + timeoutMsg.set(PayloadKey::stateMsg, toString(AuthDecodingState::TIMEOUT)); + return timeoutMsg; + } }; struct ArchiveAccountManager::DeviceAuthInfo : public std::map<std::string, std::string> @@ -362,7 +367,6 @@ struct ArchiveAccountManager::DeviceAuthInfo : public std::map<std::string, std: static constexpr auto error = "error"sv; static constexpr auto auth_scheme = "auth_scheme"sv; static constexpr auto peer_id = "peer_id"sv; - static constexpr auto peer_device_id = "peer_device_id"sv; static constexpr auto auth_error = "auth_error"sv; static constexpr auto peer_address = "peer_address"sv; @@ -375,9 +379,11 @@ struct ArchiveAccountManager::DeviceAuthInfo : public std::map<std::string, std: DeviceAuthInfo(const Map& map) : Map(map) {} + DeviceAuthInfo(Map&& map) + : Map(std::move(map)) + {} - void set(std::string_view key, std::string_view value) - { + void set(std::string_view key, std::string_view value) { emplace(std::string(key), std::string(value)); } @@ -424,18 +430,11 @@ struct ArchiveAccountManager::DeviceContextBase constexpr std::string_view formattedAuthState() const { return toString(state); } - AuthMsg createTimeoutMsg() const - { - AuthMsg timeoutMsg; - timeoutMsg.set(PayloadKey::stateMsg, std::string(toString(AuthDecodingState::TIMEOUT))); - return timeoutMsg; - } - bool handleTimeoutMessage(const AuthMsg& msg) { auto stateMsgIt = msg.find(PayloadKey::stateMsg); if (stateMsgIt != msg.payload.end()) { - if (stateMsgIt->second == std::string(toString(AuthDecodingState::TIMEOUT))) { + if (stateMsgIt->second == toString(AuthDecodingState::TIMEOUT)) { this->state = AuthDecodingState::TIMEOUT; return true; } @@ -447,7 +446,7 @@ struct ArchiveAccountManager::DeviceContextBase { auto stateMsgIt = msg.find(PayloadKey::stateMsg); if (stateMsgIt != msg.payload.end()) { - if (stateMsgIt->second == std::string(toString(AuthDecodingState::CANCELED))) { + if (stateMsgIt->second == toString(AuthDecodingState::CANCELED)) { this->state = AuthDecodingState::CANCELED; return true; } @@ -515,7 +514,7 @@ struct ArchiveAccountManager::AddDeviceContext : public DeviceContextBase AuthMsg createCanceledMsg() const { AuthMsg timeoutMsg; - timeoutMsg.set(PayloadKey::stateMsg, std::string(toString(AuthDecodingState::CANCELED))); + timeoutMsg.set(PayloadKey::stateMsg, toString(AuthDecodingState::CANCELED)); return timeoutMsg; } }; @@ -645,7 +644,6 @@ ArchiveAccountManager::startLoadArchiveFromDevice(const std::shared_ptr<AuthCont ctx->linkDevCtx->tempConnMgr.onChannelRequest( [wthis, ctx](const std::shared_ptr<dht::crypto::Certificate>& cert, const std::string& name) { - constexpr auto CHANNEL_SCHEME = "auth:"sv; std::string_view url(name); if (!starts_with(url, CHANNEL_SCHEME)) { JAMI_WARNING( @@ -677,7 +675,7 @@ ArchiveAccountManager::startLoadArchiveFromDevice(const std::shared_ptr<AuthCont ctx->linkDevCtx->channel = socket; ctx->timeout = std::make_unique<asio::steady_timer>(*Manager::instance().ioContext()); - ctx->timeout->expires_from_now(5min); + ctx->timeout->expires_from_now(OP_TIMEOUT); ctx->timeout->async_wait([c = std::weak_ptr(ctx), socket](const std::error_code& ec) { if (ec) { return; @@ -688,9 +686,8 @@ ArchiveAccountManager::startLoadArchiveFromDevice(const std::shared_ptr<AuthCont JAMI_WARNING("[LinkDevice] timeout: {}", socket->name()); // Create and send timeout message - auto timeoutMsg = ctx->linkDevCtx->createTimeoutMsg(); msgpack::sbuffer buffer(UINT16_MAX); - msgpack::pack(buffer, timeoutMsg); + msgpack::pack(buffer, AuthMsg::timeout()); std::error_code ec; socket->write(reinterpret_cast<const unsigned char*>(buffer.data()), buffer.size(), @@ -764,7 +761,7 @@ ArchiveAccountManager::startLoadArchiveFromDevice(const std::shared_ptr<AuthCont return len; } AuthMsg toSend; - bool shouldShutDown = false; + bool shouldShutdown = false; auto accDataIt = toRecv.find(PayloadKey::accData); bool shouldLoadArchive = accDataIt != toRecv.payload.end(); @@ -821,7 +818,7 @@ ArchiveAccountManager::startLoadArchiveFromDevice(const std::shared_ptr<AuthCont // at this point we suppose to have archive. If not, export failed. // Update state and signal will be handeled onShutdown ctx->linkDevCtx->state = AuthDecodingState::ERR; - shouldShutDown = true; + shouldShutdown = true; } } @@ -848,10 +845,10 @@ ArchiveAccountManager::startLoadArchiveFromDevice(const std::shared_ptr<AuthCont ctx->linkDevCtx->archiveTransferredWithoutFailure = false; JAMI_WARNING("[LinkDevice] NEW: Error reading archive."); } - shouldShutDown = true; + shouldShutdown = true; } - if (shouldShutDown) { + if (shouldShutdown) { ctx->linkDevCtx->channel->shutdown(); } @@ -915,22 +912,24 @@ ArchiveAccountManager::addDevice(const std::string& uriProvided, channelHandler->connect( dht::InfoHash(peerTempAcc), - fmt::format("auth:{}", peerCodeS), - [this, auth_scheme, ctx](std::shared_ptr<dhtnet::ChannelSocket> socket, + fmt::format("{}{}", CHANNEL_SCHEME, peerCodeS), + [wthis = weak(), auth_scheme, ctx, accountId=accountId_](std::shared_ptr<dhtnet::ChannelSocket> socket, const dht::InfoHash& infoHash) { - if (!socket) { + auto this_ = wthis.lock(); + if (!socket || !this_) { JAMI_WARNING( "[LinkDevice] Invalid socket event while AccountManager connecting."); - authCtx_.reset(); + if (this_) + this_->authCtx_.reset(); emitSignal<libjami::ConfigurationSignal::AddDeviceStateChanged>( - accountId_, + accountId, ctx->token, static_cast<uint8_t>(DeviceAuthState::DONE), DeviceAuthInfo::createError(DeviceAuthInfo::Error::NETWORK)); } else { - if (!doAddDevice(auth_scheme, ctx, socket)) + if (!this_->doAddDevice(auth_scheme, ctx, socket)) emitSignal<libjami::ConfigurationSignal::AddDeviceStateChanged>( - accountId_, + accountId, ctx->token, static_cast<uint8_t>(DeviceAuthState::DONE), DeviceAuthInfo::createError(DeviceAuthInfo::Error::UNKNOWN)); @@ -964,9 +963,9 @@ ArchiveAccountManager::doAddDevice(std::string_view scheme, ctx->addDeviceCtx->state = AuthDecodingState::HANDSHAKE; ctx->timeout = std::make_unique<asio::steady_timer>(*Manager::instance().ioContext()); - ctx->timeout->expires_from_now(5min); + ctx->timeout->expires_from_now(OP_TIMEOUT); ctx->timeout->async_wait( - [wthis = weak_from_this(), wctx = std::weak_ptr(ctx)](const std::error_code& ec) { + [wthis = weak(), wctx = std::weak_ptr(ctx)](const std::error_code& ec) { if (ec) { return; } @@ -977,9 +976,8 @@ ArchiveAccountManager::doAddDevice(std::string_view scheme, JAMI_WARNING("[LinkDevice] Timeout for addDevice."); // Create and send timeout message - auto timeoutMsg = ctx->linkDevCtx->createTimeoutMsg(); msgpack::sbuffer buffer(UINT16_MAX); - msgpack::pack(buffer, timeoutMsg); + msgpack::pack(buffer, AuthMsg::timeout()); std::error_code ec; ctx->addDeviceCtx->channel->write(reinterpret_cast<const unsigned char*>( buffer.data()), @@ -1085,7 +1083,7 @@ ArchiveAccountManager::doAddDevice(std::string_view scheme, } AuthMsg toSend; bool shouldSendMsg = false; - bool shouldShutDown = false; + bool shouldShutdown = false; bool shouldSendArchive = false; // we expect to be receiving credentials in this state and we know the archive is encrypted @@ -1095,51 +1093,42 @@ ArchiveAccountManager::doAddDevice(std::string_view scheme, JAMI_DEBUG("[LinkDevice] EXPORTING: addDevice: setOnRecv: verifying sent " "credentials from NEW"); shouldSendMsg = true; - // check if the password is valid... if so then send the unencrypyted archive data - // over the tls channel as a compressed file this will involve (EXPORTING:) unzip, - // unencrypt, send, (NEW:) recv, encrypt w new salt, compress, write to system file - // (ONLY DO EXPORTING HERE) check if password is valid const auto& passwordIt = toRecv.find(PayloadKey::password); - - bool passValid = this_->isPasswordValid(toRecv.at(PayloadKey::password)); - JAMI_DEBUG("[LinkDevice] EXPORTING: {} password received for authentication.", - passValid ? "Valid" : "Invalid"); - if (passValid) { + if (passwordIt != toRecv.payload.end()) { // try and decompress archive for xfer - shouldSendArchive = true; try { JAMI_DEBUG("[LinkDevice] Injecting account archive into outbound message."); ctx->addDeviceCtx->accData = this_ ->readArchive(fileutils::ARCHIVE_AUTH_SCHEME_PASSWORD, - toRecv.at(PayloadKey::password)) + passwordIt->second) .serialize(); - - JAMI_DEBUG("[LinkDevice] Injected account archive into outbound message.\n{}", - ctx->addDeviceCtx->accData); + shouldSendArchive = true; + JAMI_DEBUG("[LinkDevice] Sending account archive."); } catch (...) { ctx->addDeviceCtx->state = AuthDecodingState::ERR; JAMI_DEBUG("[LinkDevice] Finished reading archive: FAILURE"); shouldSendArchive = false; } - shouldShutDown = true; - } else { // pass is not valid + } + if (!shouldSendArchive) { + // pass is not valid if (ctx->addDeviceCtx->numTries < ctx->addDeviceCtx->maxTries) { // can retry auth ctx->addDeviceCtx->numTries++; - JAMI_DEBUG("[LinkDevice] Incorrect password was submitted to this server... " - "allowing a retry. {}", - ctx->addDeviceCtx->numTries); + JAMI_DEBUG("[LinkDevice] Incorrect password received. " + "Attempt {} out of {}.", + ctx->addDeviceCtx->numTries, + ctx->addDeviceCtx->maxTries); toSend.set(PayloadKey::passwordCorrect, "false"); toSend.set(PayloadKey::canRetry, "true"); } else { // cannot retry auth - JAMI_DEBUG("[LinkDevice] Incorrect password was submitted to this server... " - "NOT allowing a retry because threshold already reached!"); + JAMI_WARNING("[LinkDevice] Incorrect password received, maximum attempts reached."); toSend.set(PayloadKey::canRetry, "false"); ctx->addDeviceCtx->state = AuthDecodingState::AUTH_ERROR; - shouldShutDown = true; + shouldShutdown = true; } } } @@ -1152,7 +1141,7 @@ ArchiveAccountManager::doAddDevice(std::string_view scheme, ctx->token, static_cast<uint8_t>(DeviceAuthState::IN_PROGRESS), DeviceAuthInfo {}); - shouldShutDown = true; + shouldShutdown = true; shouldSendMsg = true; ctx->addDeviceCtx->archiveTransferredWithoutFailure = true; try { @@ -1177,7 +1166,7 @@ ArchiveAccountManager::doAddDevice(std::string_view scheme, ec); } - if (shouldShutDown) { + if (shouldShutdown) { ctx->addDeviceCtx->channel->shutdown(); } @@ -1278,7 +1267,7 @@ ArchiveAccountManager::loadFromDHT(const std::shared_ptr<AuthContext>& ctx) } }; - auto search = [ctx, searchEnded, w = weak_from_this()](bool previous) { + auto search = [ctx, searchEnded, w = weak()](bool previous) { std::vector<uint8_t> key; dht::InfoHash loc; auto& s = previous ? ctx->dhtContext->stateOld : ctx->dhtContext->stateNew; @@ -1310,8 +1299,7 @@ ArchiveAccountManager::loadFromDHT(const std::shared_ptr<AuthContext>& ctx) [ctx, decrypted = std::move(decrypted), w] { try { auto archive = AccountArchive(decrypted); - if (auto sthis = std::static_pointer_cast<ArchiveAccountManager>( - w.lock())) { + if (auto sthis = w.lock()) { if (ctx->dhtContext) { ctx->dhtContext->dht.join(); ctx->dhtContext.reset(); @@ -1705,13 +1693,13 @@ ArchiveAccountManager::revokeDevice(const std::string& device, password, device, cb, - w = weak_from_this()]( + w = weak()]( const std::shared_ptr<dht::crypto::Certificate>& crt) mutable { if (not crt) { cb(RevokeDeviceResult::ERROR_NETWORK); return; } - auto this_ = std::static_pointer_cast<ArchiveAccountManager>(w.lock()); + auto this_ = w.lock(); if (not this_) return; this_->info_->contacts->foundAccountDevice(crt); diff --git a/src/jamidht/archive_account_manager.h b/src/jamidht/archive_account_manager.h index 35f57846d57fafdefe6951f4168597c015644445..5d0269827e031a13af45996a1d3f0a9aa29f45b7 100644 --- a/src/jamidht/archive_account_manager.h +++ b/src/jamidht/archive_account_manager.h @@ -87,14 +87,10 @@ public: const std::string& password); bool isPasswordValid(const std::string& password) override; - // link device: NEW: for authenticating exporting account to another device but can be used for - // any sort of authentication in the future bool provideAccountAuthentication(const std::string& credentialsFromUser, const std::string& scheme); #if HAVE_RINGNS - /*void lookupName(const std::string& name, LookupCallback cb) override; - void lookupAddress(const std::string& address, LookupCallback cb) override;*/ void registerName(const std::string& name, std::string_view scheme, const std::string& password, @@ -138,7 +134,6 @@ private: struct DecodingContext; struct AuthMsg; struct DeviceAuthInfo; - struct PayloadKey; std::shared_ptr<AuthContext> authCtx_; void createAccount(AuthContext& ctx);