30#include <dhtnet/multiplexed_socket.h>
31#include <dhtnet/channel_utils.h>
32#include <opendht/dhtrunner.h>
33#include <opendht/thread_pool.h>
49 std::string deviceName,
50 std::unique_ptr<AccountCredentials> credentials,
55 JAMI_WARNING(
"[Account {}] [Auth] starting authentication with scheme '{}'",
accountId_, credentials->scheme);
56 auto ctx = std::make_shared<AuthContext>();
60 ctx->deviceName = std::move(deviceName);
62 ctx->onSuccess = std::move(onSuccess);
63 ctx->onFailure = std::move(onFailure);
65 if (
not ctx->credentials) {
71 if (
ctx->credentials->scheme ==
"p2p") {
72 JAMI_DEBUG(
"[LinkDevice] Importing account via p2p scheme.");
73 startLoadArchiveFromDevice(
ctx);
77 dht::ThreadPool::computation().run([
ctx = std::move(
ctx),
wthis = weak()] {
82 if (
ctx->credentials->scheme ==
"file") {
84 this_->loadFromFile(*ctx);
87 bool hasArchive = not ctx->credentials->uri.empty()
88 and std::filesystem::is_regular_file(ctx->credentials->uri);
91 if (ctx->credentials->updateIdentity.first and ctx->credentials->updateIdentity.second
92 and needsMigration(this_->accountId_, ctx->credentials->updateIdentity)) {
93 this_->migrateAccount(*ctx);
95 this_->loadFromFile(*ctx);
97 }
else if (
ctx->credentials->updateIdentity.first
and ctx->credentials->updateIdentity.second) {
98 auto future_keypair = dht::ThreadPool::computation().get<dev::KeyPair>(&dev::KeyPair::create);
100 JAMI_WARNING(
"[Account {}] [Auth] Converting certificate from old account {}",
102 ctx->credentials->updateIdentity.first->getPublicKey().getId().to_view());
103 a.id = std::move(ctx->credentials->updateIdentity);
105 a.ca_key = std::make_shared<dht::crypto::PrivateKey>(
106 fileutils::loadFile(
"ca.key", this_->path_));
109 this_->updateCertificates(
a,
ctx->credentials->updateIdentity);
111 this_->onArchiveLoaded(*
ctx, std::move(
a),
false);
116 }
catch (
const std::exception&
e) {
117 ctx->onFailure(AuthError::UNKNOWN,
e.what());
123ArchiveAccountManager::updateCertificates(AccountArchive& archive, dht::crypto::Identity& device)
125 JAMI_WARNING(
"[Account {}] [Auth] Updating certificates", accountId_);
126 using Certificate = dht::crypto::Certificate;
129 if (not archive.id.first or not *archive.id.first or not archive.id.second or not archive.ca_key
130 or not *archive.ca_key)
134 bool updated =
false;
136 auto& cert = archive.id.second;
137 auto ca = cert->issuer;
139 if (not ca or (not ca->issuer and (not ca->isCA() or ca->getExpiration() < clock::now()))) {
140 ca = std::make_shared<Certificate>(Certificate::generate(*archive.ca_key,
"Jami CA", {},
true));
142 JAMI_LOG(
"[Account {}] [Auth] CA certificate re-generated", accountId_);
146 if (updated or not cert->isCA() or cert->getExpiration() < clock::now()) {
147 cert = std::make_shared<Certificate>(
148 Certificate::generate(*archive.id.first,
"Jami", dht::crypto::Identity {archive.ca_key, ca},
true));
150 JAMI_LOG(
"[Account {}] [Auth] Account certificate for {} re-generated", accountId_, cert->getId());
153 if (updated and device.first and *device.first) {
155 device.second = std::make_shared<Certificate>(Certificate::generate(*device.first,
"Jami device", archive.id));
156 JAMI_LOG(
"[Account {}] [Auth] Device certificate re-generated", accountId_);
163ArchiveAccountManager::setValidity(std::string_view scheme,
164 const std::string& password,
165 dht::crypto::Identity& device,
166 const dht::InfoHash&
id,
169 auto archive = readArchive(scheme, password);
171 if (not archive.id.first or not *archive.id.first or not archive.id.second or not archive.ca_key
172 or not *archive.ca_key)
175 auto updated =
false;
178 JAMI_WARNING(
"[Account {}] [Auth] Updating validity for certificate with id: {}", accountId_,
id);
180 JAMI_WARNING(
"[Account {}] [Auth] Updating validity for certificates", accountId_);
182 auto& cert = archive.id.second;
183 auto ca = cert->issuer;
189 if (not
id or ca->getId() ==
id) {
190 ca->setValidity(*archive.ca_key, validity);
192 JAMI_LOG(
"[Account {}] [Auth] CA certificate re-generated", accountId_);
196 if (updated or not
id or cert->getId() ==
id) {
197 cert->setValidity(dht::crypto::Identity {archive.ca_key, ca}, validity);
198 device.second->issuer = cert;
200 JAMI_LOG(
"[Account {}] [Auth] Jami certificate re-generated", accountId_);
204 archive.save(fileutils::getFullPath(path_, archivePath_), scheme, password);
207 if (updated or not
id or device.second->getId() ==
id) {
209 device.second->setValidity(archive.id, validity);
217ArchiveAccountManager::createAccount(AuthContext&
ctx)
220 auto ca = dht::crypto::generateIdentity(
"Jami CA");
221 if (!ca.first || !ca.second) {
222 throw std::runtime_error(
"Unable to generate CA for this account.");
224 a.
id = dht::crypto::generateIdentity(
"Jami", ca, 4096,
true);
225 if (!a.
id.first || !a.
id.second) {
226 throw std::runtime_error(
"Unable to generate identity for this account.");
228 JAMI_WARNING(
"[Account {}] [Auth] New account: CA: {}, ID: {}",
231 a.
id.second->getId());
234 a.
eth_key = keypair.secret().makeInsecure().asBytes();
235 onArchiveLoaded(ctx, std::move(a),
false);
239ArchiveAccountManager::loadFromFile(AuthContext& ctx)
241 JAMI_WARNING(
"[Account {}] [Auth] Loading archive from: {}", accountId_, ctx.credentials->uri.c_str());
242 AccountArchive archive;
244 archive = AccountArchive(ctx.credentials->uri, ctx.credentials->password_scheme, ctx.credentials->password);
245 }
catch (
const std::exception& ex) {
246 JAMI_WARNING(
"[Account {}] [Auth] Unable to read archive file: {}", accountId_, ex.what());
247 ctx.onFailure(AuthError::INVALID_ARGUMENTS, ex.what());
250 onArchiveLoaded(ctx, std::move(archive),
false);
257static constexpr std::string_view
261 case AuthDecodingState::HANDSHAKE:
262 return "HANDSHAKE"sv;
263 case AuthDecodingState::EST:
265 case AuthDecodingState::AUTH:
267 case AuthDecodingState::DATA:
269 case AuthDecodingState::AUTH_ERROR:
270 return "AUTH_ERROR"sv;
271 case AuthDecodingState::DONE:
273 case AuthDecodingState::TIMEOUT:
275 case AuthDecodingState::CANCELED:
277 case AuthDecodingState::ERR:
283namespace PayloadKey {
294 uint8_t schemeId {0};
296 MSGPACK_DEFINE_MAP(schemeId, payload)
298 void set(
std::string_view key,
std::string_view value) { payload.emplace(std::string(key), std::string(value)); }
300 auto find(std::string_view key)
const {
return payload.find(std::string(key)); }
302 auto at(std::string_view key)
const {
return payload.at(std::string(key)); }
308 std::string logStr = fmt::format(
"=========\nscheme: {}\n", schemeId);
309 for (
const auto& [msgKey, msgVal] : payload) {
310 logStr += fmt::format(
" - {}: {}\n", msgKey, msgVal);
312 logStr +=
"=========";
319 timeoutMsg.
set(PayloadKey::stateMsg,
toString(AuthDecodingState::TIMEOUT));
327 static constexpr auto token =
"token"sv;
328 static constexpr auto error =
"error"sv;
329 static constexpr auto auth_scheme =
"auth_scheme"sv;
330 static constexpr auto peer_id =
"peer_id"sv;
331 static constexpr auto auth_error =
"auth_error"sv;
332 static constexpr auto peer_address =
"peer_address"sv;
337 using Map = std::map<std::string, std::string>;
347 void set(std::string_view key, std::string_view value) { emplace(std::string(key), std::string(value)); }
359 case Error::AUTH_ERROR:
360 errStr =
"auth_error";
362 case Error::CANCELED:
381 bool authEnabled {
false};
382 bool archiveTransferredWithoutFailure {
false};
387 , state(initialState)
394 auto stateMsgIt = msg.
find(PayloadKey::stateMsg);
395 if (stateMsgIt != msg.
payload.end()) {
396 if (stateMsgIt->second ==
toString(AuthDecodingState::TIMEOUT)) {
397 this->state = AuthDecodingState::TIMEOUT;
406 auto stateMsgIt = msg.
find(PayloadKey::stateMsg);
407 if (stateMsgIt != msg.
payload.end()) {
408 if (stateMsgIt->second ==
toString(AuthDecodingState::CANCELED)) {
409 this->state = AuthDecodingState::CANCELED;
418 if (state == AuthDecodingState::AUTH_ERROR) {
419 return DeviceAuthInfo::Error::AUTH_ERROR;
420 }
else if (state == AuthDecodingState::TIMEOUT) {
421 return DeviceAuthInfo::Error::TIMEOUT;
422 }
else if (state == AuthDecodingState::CANCELED) {
423 return DeviceAuthInfo::Error::CANCELED;
424 }
else if (state == AuthDecodingState::ERR) {
425 return DeviceAuthInfo::Error::UNKNOWN;
426 }
else if (archiveTransferredWithoutFailure) {
427 return DeviceAuthInfo::Error::NONE;
429 return DeviceAuthInfo::Error::NETWORK;
434 return state == AuthDecodingState::DONE || state == AuthDecodingState::ERR
435 || state == AuthDecodingState::AUTH_ERROR || state == AuthDecodingState::TIMEOUT
436 || state == AuthDecodingState::CANCELED;
444 unsigned numOpenChannels {0};
445 unsigned maxOpenChannels {1};
446 std::shared_ptr<dhtnet::ChannelSocket>
channel;
447 msgpack::unpacker pac {[](msgpack::type::object_type, std::size_t,
void*) {
return true; },
nullptr, 512};
448 std::string authScheme {fileutils::ARCHIVE_AUTH_SCHEME_NONE};
449 std::string credentialsFromUser {
""};
454 , tempConnMgr(config)
460 unsigned numTries {0};
461 unsigned maxTries {3};
462 std::shared_ptr<dhtnet::ChannelSocket>
channel;
468 , channel(
std::move(c))
474 timeoutMsg.
set(PayloadKey::stateMsg,
toString(AuthDecodingState::CANCELED));
480ArchiveAccountManager::provideAccountAuthentication(
const std::string& key,
const std::string& scheme)
482 if (scheme != fileutils::ARCHIVE_AUTH_SCHEME_PASSWORD) {
483 JAMI_ERROR(
"[LinkDevice] Unsupported account authentication scheme attempted.");
492 if (
ctx->linkDevCtx->state != AuthDecodingState::AUTH) {
493 JAMI_WARNING(
"[LinkDevice] Invalid state for providing account authentication.");
497 ctx->linkDevCtx->authScheme = scheme;
498 ctx->linkDevCtx->credentialsFromUser = key;
500 ctx->linkDevCtx->state = AuthDecodingState::DATA;
501 emitSignal<libjami::ConfigurationSignal::DeviceAuthStateChanged>(
ctx->accountId,
502 static_cast<uint8_t
>(DeviceAuthState::IN_PROGRESS),
505 dht::ThreadPool::io().run([key = std::move(key), scheme,
ctx]()
mutable {
507 toSend.
set(PayloadKey::password, std::move(key));
508 msgpack::sbuffer buffer(UINT16_MAX);
510 msgpack::pack(buffer, toSend);
513 ctx->linkDevCtx->channel->write(
reinterpret_cast<const unsigned char*
>(buffer.data()), buffer.size(), ec);
514 }
catch (
const std::exception& e) {
515 JAMI_WARNING(
"[LinkDevice] Failed to send password over auth ChannelSocket. Channel "
525ArchiveAccountManager::startLoadArchiveFromDevice(
const std::shared_ptr<AuthContext>&
ctx)
528 JAMI_WARNING(
"[LinkDevice] Already loading archive from device.");
529 ctx->onFailure(AuthError::INVALID_ARGUMENTS,
"Already loading archive from device.");
532 JAMI_DEBUG(
"[LinkDevice] Starting load archive from device {} {}.", fmt::ptr(
this), fmt::ptr(ctx));
535 dht::ThreadPool::computation().run([ctx, wthis = weak()] {
536 auto ca = dht::crypto::generateEcIdentity(
"Jami Temporary CA");
537 if (!ca.first || !ca.second) {
538 throw std::runtime_error(
"[LinkDevice] Can't generate CA for this account.");
541 auto user = dht::crypto::generateIdentity(
"Jami Temporary User", ca, 4096,
true);
542 if (!user.first || !user.second) {
543 throw std::runtime_error(
"[LinkDevice] Can't generate identity for this account.");
546 auto this_ = wthis.lock();
548 JAMI_WARNING(
"[LinkDevice] Failed to get the ArchiveAccountManager.");
552 auto config = std::make_shared<dhtnet::ConnectionManager::Config>();
553 config->id = dht::crypto::generateIdentity(
"Jami Temporary device", user);
554 config->ioContext = Manager::instance().ioContext();
555 config->factory = Manager::instance().getIceTransportFactory();
556 config->rng = std::make_unique<std::mt19937_64>(Manager::instance().getSeededRandomEngine());
557 config->turnEnabled =
true;
558 config->turnServer = DEFAULT_TURN_SERVER;
559 config->turnServerUserName = DEFAULT_TURN_USERNAME;
560 config->turnServerPwd = DEFAULT_TURN_PWD;
561 config->turnServerRealm = DEFAULT_TURN_REALM;
563 ctx->linkDevCtx = std::make_shared<LinkDeviceContext>(config);
564 JAMI_LOG(
"[LinkDevice] Established linkDevCtx. {} {} {}.",
567 fmt::ptr(ctx->linkDevCtx));
570 ctx->linkDevCtx->opId = std::uniform_int_distribution<uint64_t>(100000, 999999)(*config->rng);
572 ctx->linkDevCtx->tempConnMgr.oniOSConnected(
573 [&](
const std::string& connType, dht::InfoHash peer_h) {
return false; });
575 ctx->linkDevCtx->tempConnMgr.dhtStarted();
577 auto accountScheme = fmt::format(
"{}{}/{}",
579 ctx->linkDevCtx->tmpId.second->getLongId(),
580 ctx->linkDevCtx->opId);
581 JAMI_LOG(
"[LinkDevice] auth scheme will be: {}", accountScheme);
584 info.set(DeviceAuthInfo::token, accountScheme);
586 ctx->linkDevCtx->tempConnMgr.onICERequest([wctx = std::weak_ptr(ctx)](
const DeviceId& ) {
587 if (
auto ctx = wctx.lock()) {
588 emitSignal<libjami::ConfigurationSignal::DeviceAuthStateChanged>(ctx->accountId,
589 static_cast<uint8_t>(
590 DeviceAuthState::CONNECTING),
597 ctx->linkDevCtx->tempConnMgr.onChannelRequest(
598 [wthis, ctx](
const std::shared_ptr<dht::crypto::Certificate>& ,
const std::string& name) {
599 std::string_view url(name);
600 if (!starts_with(url, CHANNEL_SCHEME)) {
601 JAMI_WARNING(
"[LinkDevice] Temporary connection manager received invalid scheme: {}", name);
607 if (ctx->linkDevCtx->opId == parsedOpId
608 && ctx->linkDevCtx->numOpenChannels < ctx->linkDevCtx->maxOpenChannels) {
609 ctx->linkDevCtx->numOpenChannels++;
610 JAMI_DEBUG(
"[LinkDevice] Opening channel ({}/{}): {}",
611 ctx->linkDevCtx->numOpenChannels,
612 ctx->linkDevCtx->maxOpenChannels,
619 ctx->linkDevCtx->tempConnMgr.onConnectionReady([ctx,
621 wthis](
const DeviceId& ,
622 const std::string& name,
623 const std::shared_ptr<dhtnet::ChannelSocket>& socket) {
625 JAMI_WARNING(
"[LinkDevice] Temporary connection manager received invalid socket.");
627 ctx->timeout->cancel();
628 ctx->timeout.reset();
629 ctx->linkDevCtx->numOpenChannels--;
630 if (
auto sthis = wthis.lock())
631 sthis->authCtx_.reset();
632 ctx->linkDevCtx->state = AuthDecodingState::ERR;
633 emitSignal<libjami::ConfigurationSignal::DeviceAuthStateChanged>(ctx->accountId,
634 static_cast<uint8_t
>(
635 DeviceAuthState::DONE),
636 DeviceAuthInfo::createError(
637 DeviceAuthInfo::Error::NETWORK));
640 ctx->linkDevCtx->channel = socket;
642 ctx->timeout = std::make_unique<asio::steady_timer>(*Manager::instance().ioContext());
643 ctx->timeout->expires_after(OP_TIMEOUT);
644 ctx->timeout->async_wait([c = std::weak_ptr(ctx), socket](
const std::error_code& ec) {
648 if (
auto ctx = c.lock()) {
649 if (!ctx->linkDevCtx->isCompleted()) {
650 ctx->linkDevCtx->state = AuthDecodingState::TIMEOUT;
651 JAMI_WARNING(
"[LinkDevice] timeout: {}", socket->name());
654 msgpack::sbuffer buffer(UINT16_MAX);
655 msgpack::pack(buffer, AuthMsg::timeout());
657 socket->write(reinterpret_cast<const unsigned char*>(buffer.data()), buffer.size(), ec);
663 socket->onShutdown([ctx, name, wthis](
const std::error_code& ) {
664 JAMI_WARNING(
"[LinkDevice] Temporary connection manager closing socket: {}", name);
666 ctx->timeout->cancel();
667 ctx->timeout.reset();
668 ctx->linkDevCtx->numOpenChannels--;
669 ctx->linkDevCtx->channel.reset();
670 if (
auto sthis = wthis.lock())
671 sthis->authCtx_.reset();
673 DeviceAuthInfo::Error error = ctx->linkDevCtx->getErrorState();
674 emitSignal<libjami::ConfigurationSignal::DeviceAuthStateChanged>(ctx->accountId,
675 static_cast<uint8_t
>(
676 DeviceAuthState::DONE),
677 DeviceAuthInfo::createError(error));
680 socket->setOnRecv(dhtnet::buildMsgpackReader<AuthMsg>([ctx, wthis](AuthMsg&& toRecv) {
681 if (!ctx || !wthis.lock())
682 return std::make_error_code(std::errc::operation_canceled);
683 JAMI_DEBUG(
"[LinkDevice] NEW: Successfully unpacked message from source\n{}", toRecv.formatMsg());
684 JAMI_DEBUG(
"[LinkDevice] NEW: State is {}:{}",
685 ctx->linkDevCtx->scheme,
686 ctx->linkDevCtx->formattedAuthState());
689 if (toRecv.schemeId != 0) {
690 JAMI_WARNING(
"[LinkDevice] NEW: Unsupported scheme received from source");
691 ctx->linkDevCtx->state = AuthDecodingState::ERR;
692 return std::make_error_code(std::errc::operation_canceled);
696 if (ctx->linkDevCtx->handleCanceledMessage(toRecv)) {
698 return std::make_error_code(std::errc::operation_canceled);
701 bool shouldShutdown =
false;
702 auto accDataIt = toRecv.find(PayloadKey::accData);
703 bool shouldLoadArchive = accDataIt != toRecv.payload.end();
705 if (ctx->linkDevCtx->state == AuthDecodingState::HANDSHAKE) {
706 auto peerCert = ctx->linkDevCtx->channel->peerCertificate();
707 auto authScheme = toRecv.at(PayloadKey::authScheme);
708 ctx->linkDevCtx->authEnabled =
authScheme != fileutils::ARCHIVE_AUTH_SCHEME_NONE;
710 JAMI_DEBUG(
"[LinkDevice] NEW: Auth scheme from payload is '{}'", authScheme);
711 ctx->linkDevCtx->state = AuthDecodingState::AUTH;
713 info.set(DeviceAuthInfo::auth_scheme, authScheme);
714 info.set(DeviceAuthInfo::peer_id, peerCert->issuer->getId().toString());
715 emitSignal<libjami::ConfigurationSignal::DeviceAuthStateChanged>(ctx->accountId,
716 static_cast<uint8_t
>(
717 DeviceAuthState::AUTHENTICATING),
719 }
else if (ctx->linkDevCtx->state == AuthDecodingState::DATA) {
720 auto passwordCorrectIt = toRecv.find(PayloadKey::passwordCorrect);
721 auto canRetry = toRecv.find(PayloadKey::canRetry);
724 if (canRetry != toRecv.payload.end() &&
canRetry->second ==
"false") {
725 JAMI_DEBUG(
"[LinkDevice] Authentication failed: maximum retry attempts reached");
726 ctx->linkDevCtx->state = AuthDecodingState::AUTH_ERROR;
727 return std::make_error_code(std::errc::operation_canceled);
731 if (passwordCorrectIt != toRecv.payload.end() && passwordCorrectIt->second ==
"false") {
732 ctx->linkDevCtx->state = AuthDecodingState::AUTH;
734 JAMI_DEBUG(
"[LinkDevice] NEW: Password incorrect.");
735 auto peerCert = ctx->linkDevCtx->channel->peerCertificate();
736 auto peer_id = peerCert->issuer->getId().toString();
739 auto authScheme = fileutils::ARCHIVE_AUTH_SCHEME_PASSWORD;
742 info.set(DeviceAuthInfo::auth_scheme, authScheme);
743 info.set(DeviceAuthInfo::peer_id, peer_id);
744 info.set(DeviceAuthInfo::auth_error,
"invalid_credentials");
746 emitSignal<libjami::ConfigurationSignal::DeviceAuthStateChanged>(
747 ctx->accountId,
static_cast<uint8_t
>(DeviceAuthState::AUTHENTICATING), info);
748 return std::error_code();
751 if (!shouldLoadArchive) {
752 JAMI_DEBUG(
"[LinkDevice] NEW: no archive received.");
755 ctx->linkDevCtx->state = AuthDecodingState::ERR;
756 shouldShutdown =
true;
761 if (shouldLoadArchive) {
762 emitSignal<libjami::ConfigurationSignal::DeviceAuthStateChanged>(ctx->accountId,
763 static_cast<uint8_t
>(
764 DeviceAuthState::IN_PROGRESS),
767 auto archive = AccountArchive(std::string_view(accDataIt->second));
768 if (
auto this_ = wthis.lock()) {
769 JAMI_DEBUG(
"[LinkDevice] NEW: Reading archive from peer.");
770 this_->onArchiveLoaded(*ctx, std::move(archive),
true);
771 JAMI_DEBUG(
"[LinkDevice] NEW: Successfully loaded archive.");
772 ctx->linkDevCtx->archiveTransferredWithoutFailure =
true;
774 ctx->linkDevCtx->archiveTransferredWithoutFailure =
false;
775 JAMI_ERROR(
"[LinkDevice] NEW: Failed to load account because of "
776 "null ArchiveAccountManager!");
778 }
catch (
const std::exception& e) {
779 ctx->linkDevCtx->state = AuthDecodingState::ERR;
780 ctx->linkDevCtx->archiveTransferredWithoutFailure =
false;
781 JAMI_WARNING(
"[LinkDevice] NEW: Error reading archive.");
783 shouldShutdown =
true;
786 return shouldShutdown ? std::make_error_code(std::errc::operation_canceled) :
std::error_code();
789 ctx->linkDevCtx->state = AuthDecodingState::HANDSHAKE;
793 JAMI_DEBUG(
"[LinkDevice] NEW: Packing first message for SOURCE.\nCurrent state is: "
797 ctx->linkDevCtx->formattedAuthState());
798 msgpack::sbuffer buffer(UINT16_MAX);
799 msgpack::pack(buffer, toSend);
801 ctx->linkDevCtx->channel->write(
reinterpret_cast<const unsigned char*
>(buffer.data()), buffer.size(), ec);
803 JAMI_LOG(
"[LinkDevice {}] Generated temporary account.", ctx->linkDevCtx->tmpId.second->getId());
806 emitSignal<libjami::ConfigurationSignal::DeviceAuthStateChanged>(ctx->accountId,
807 static_cast<uint8_t
>(
808 DeviceAuthState::TOKEN_AVAILABLE),
811 JAMI_DEBUG(
"[LinkDevice] Starting load archive from device END {} {}.", fmt::ptr(
this), fmt::ptr(ctx));
815ArchiveAccountManager::addDevice(
const std::string& uriProvided,
816 std::string_view auth_scheme,
820 JAMI_WARNING(
"[LinkDevice] addDevice: auth context already exists.");
821 return static_cast<int32_t
>(AccountManager::AddDeviceError::ALREADY_LINKING);
823 JAMI_LOG(
"[LinkDevice] ArchiveAccountManager::addDevice({}, {})", accountId_, uriProvided);
824 std::string_view url(uriProvided);
826 JAMI_ERROR(
"[LinkDevice] Invalid uri provided: {}", uriProvided);
827 return static_cast<int32_t
>(AccountManager::AddDeviceError::INVALID_URI);
831 auto slashPos = url.find(
'/');
832 if (slashPos == std::string_view::npos || (slashPos != 40 && slashPos != 64)) {
833 JAMI_ERROR(
"[LinkDevice] Invalid uri provided: {}", uriProvided);
834 return static_cast<int32_t
>(AccountManager::AddDeviceError::INVALID_URI);
836 auto peerTempAcc = url.substr(0, slashPos);
837 url.remove_prefix(slashPos + 1);
838 auto peerCodeS = url.substr(0, url.find(
'/'));
839 if (peerCodeS.size() != 6) {
840 JAMI_ERROR(
"[LinkDevice] Invalid uri provided: {}", uriProvided);
841 return static_cast<int32_t
>(AccountManager::AddDeviceError::INVALID_URI);
843 JAMI_LOG(
"[LinkDevice] ======\n * tempAcc = {}\n * code = {}", peerTempAcc, peerCodeS);
845 auto gen = Manager::instance().getSeededRandomEngine();
846 auto token = std::uniform_int_distribution<int32_t>(1, std::numeric_limits<int32_t>::max())(gen);
847 JAMI_WARNING(
"[LinkDevice] SOURCE: Creating auth context, token: {}.", token);
848 auto ctx = std::make_shared<AuthContext>();
849 ctx->accountId = accountId_;
851 ctx->credentials = std::make_unique<ArchiveAccountCredentials>();
854 auto onConnect = [wthis = weak(), auth_scheme,
ctx, accountId = accountId_](
855 std::shared_ptr<dhtnet::ChannelSocket> socket) {
856 auto this_ = wthis.lock();
857 if (!socket || !this_) {
858 JAMI_WARNING(
"[LinkDevice] Invalid socket event while AccountManager connecting.");
860 this_->authCtx_.reset();
861 emitSignal<libjami::ConfigurationSignal::AddDeviceStateChanged>(accountId,
863 static_cast<uint8_t
>(DeviceAuthState::DONE),
864 DeviceAuthInfo::createError(
865 DeviceAuthInfo::Error::NETWORK));
867 if (!this_->doAddDevice(auth_scheme,
ctx, std::move(socket)))
868 emitSignal<libjami::ConfigurationSignal::AddDeviceStateChanged>(accountId,
870 static_cast<uint8_t
>(
871 DeviceAuthState::DONE),
872 DeviceAuthInfo::createError(
873 DeviceAuthInfo::Error::UNKNOWN));
877 auto channelName = fmt::format(
"{}{}",
CHANNEL_SCHEME, peerCodeS);
878 if (peerTempAcc.size() == 40) {
879 channelHandler->
connect(dht::InfoHash(peerTempAcc),
881 [onConnect](std::shared_ptr<dhtnet::ChannelSocket> socket,
882 const dht::InfoHash& ) { onConnect(std::move(socket)); });
884 channelHandler->
connect(dht::PkId(peerTempAcc),
886 [onConnect](std::shared_ptr<dhtnet::ChannelSocket> socket,
887 const dht::PkId& ) { onConnect(std::move(socket)); });
890 runOnMainThread([token,
id = accountId_] {
891 emitSignal<libjami::ConfigurationSignal::AddDeviceStateChanged>(
id,
893 static_cast<uint8_t
>(
894 DeviceAuthState::CONNECTING),
901ArchiveAccountManager::doAddDevice(std::string_view scheme,
902 const std::shared_ptr<AuthContext>&
ctx,
903 std::shared_ptr<dhtnet::ChannelSocket> channel)
906 JAMI_WARNING(
"[LinkDevice] SOURCE: addDevice canceled.");
910 JAMI_DEBUG(
"[LinkDevice] Setting up addDevice logic on SOURCE device.");
911 JAMI_DEBUG(
"[LinkDevice] SOURCE: Creating addDeviceCtx.");
912 ctx->addDeviceCtx = std::make_unique<AddDeviceContext>(std::move(channel));
913 ctx->addDeviceCtx->authScheme = scheme;
914 ctx->addDeviceCtx->state = AuthDecodingState::HANDSHAKE;
916 ctx->timeout = std::make_unique<asio::steady_timer>(*Manager::instance().ioContext());
917 ctx->timeout->expires_after(OP_TIMEOUT);
918 ctx->timeout->async_wait([wthis = weak(), wctx = std::weak_ptr(ctx)](
const std::error_code& ec) {
921 dht::ThreadPool::io().run([wthis, wctx]() {
922 if (
auto ctx = wctx.lock()) {
923 if (!ctx->addDeviceCtx->isCompleted()) {
924 if (auto this_ = wthis.lock()) {
925 ctx->addDeviceCtx->state = AuthDecodingState::TIMEOUT;
926 JAMI_WARNING(
"[LinkDevice] Timeout for addDevice.");
929 msgpack::sbuffer buffer(UINT16_MAX);
930 msgpack::pack(buffer, AuthMsg::timeout());
932 ctx->addDeviceCtx->channel->write(reinterpret_cast<const unsigned char*>(buffer.data()),
935 ctx->addDeviceCtx->channel->shutdown();
942 JAMI_DEBUG(
"[LinkDevice] SOURCE: Creating callbacks.");
943 ctx->addDeviceCtx->channel->onShutdown([ctx, w = weak()](
const std::error_code& ) {
944 JAMI_DEBUG(
"[LinkDevice] SOURCE: Shutdown with state {}... xfer {}uccessful",
945 ctx->addDeviceCtx->formattedAuthState(),
946 ctx->addDeviceCtx->archiveTransferredWithoutFailure ?
"s" :
"uns");
949 ctx->timeout->cancel();
950 ctx->timeout.reset();
952 if (
auto this_ = w.lock()) {
953 this_->authCtx_.reset();
956 DeviceAuthInfo::Error error = ctx->addDeviceCtx->getErrorState();
957 emitSignal<libjami::ConfigurationSignal::AddDeviceStateChanged>(ctx->accountId,
959 static_cast<uint8_t
>(DeviceAuthState::DONE),
960 DeviceAuthInfo::createError(error));
965 JAMI_DEBUG(
"[LinkDevice] Setting up receiving logic callback.");
966 ctx->addDeviceCtx->channel->setOnRecv(dhtnet::buildMsgpackReader<AuthMsg>([ctx, wthis = weak()](AuthMsg&& toRecv) {
967 JAMI_DEBUG(
"[LinkDevice] Setting up receiver callback for communication logic on SOURCE device.");
970 auto this_ = wthis.lock();
972 JAMI_ERROR(
"[LinkDevice] Invalid state for ArchiveAccountManager.");
973 return std::make_error_code(std::errc::operation_canceled);
976 if (ctx->canceled || ctx->addDeviceCtx->state == AuthDecodingState::ERR) {
978 return std::make_error_code(std::errc::operation_canceled);
982 JAMI_DEBUG(
"[LinkDevice] SOURCE: addDevice: setOnRecv: handling msg from NEW");
983 JAMI_DEBUG(
"[LinkDevice] SOURCE: State is '{}'", ctx->addDeviceCtx->formattedAuthState());
988 if (toRecv.schemeId != 0) {
989 ctx->addDeviceCtx->state = AuthDecodingState::ERR;
990 JAMI_WARNING(
"[LinkDevice] Unsupported scheme received from a connection.");
993 if (ctx->addDeviceCtx->state == AuthDecodingState::ERR
994 || ctx->addDeviceCtx->state == AuthDecodingState::AUTH_ERROR) {
995 JAMI_WARNING(
"[LinkDevice] Undefined behavior encountered during a link auth session.");
996 return std::make_error_code(std::errc::operation_canceled);
999 if (ctx->addDeviceCtx->handleTimeoutMessage(toRecv)) {
1000 return std::make_error_code(std::errc::operation_canceled);
1003 bool shouldSendMsg =
false;
1004 bool shouldShutdown =
false;
1005 bool shouldSendArchive =
false;
1008 if (ctx->addDeviceCtx->state == AuthDecodingState::AUTH) {
1011 JAMI_DEBUG(
"[LinkDevice] SOURCE: addDevice: setOnRecv: verifying sent credentials from NEW");
1012 shouldSendMsg =
true;
1013 const auto& passwordIt = toRecv.find(PayloadKey::password);
1014 if (passwordIt != toRecv.payload.end()) {
1017 JAMI_DEBUG(
"[LinkDevice] Injecting account archive into outbound message.");
1018 ctx->addDeviceCtx->accData
1019 = this_->readArchive(fileutils::ARCHIVE_AUTH_SCHEME_PASSWORD, passwordIt->second).serialize();
1020 shouldSendArchive =
true;
1021 JAMI_DEBUG(
"[LinkDevice] Sending account archive.");
1022 }
catch (
const std::exception& e) {
1023 JAMI_DEBUG(
"[LinkDevice] Finished reading archive: FAILURE: {}", e.what());
1024 shouldSendArchive =
false;
1027 if (!shouldSendArchive) {
1029 ctx->addDeviceCtx->numTries++;
1030 if (ctx->addDeviceCtx->numTries < ctx->addDeviceCtx->maxTries) {
1032 JAMI_DEBUG(
"[LinkDevice] Incorrect password received. Attempt {} out of {}.",
1033 ctx->addDeviceCtx->numTries,
1034 ctx->addDeviceCtx->maxTries);
1035 toSend.set(PayloadKey::passwordCorrect,
"false");
1036 toSend.set(PayloadKey::canRetry,
"true");
1039 JAMI_WARNING(
"[LinkDevice] Incorrect password received, maximum attempts reached.");
1040 toSend.set(PayloadKey::canRetry,
"false");
1041 ctx->addDeviceCtx->state = AuthDecodingState::AUTH_ERROR;
1042 shouldShutdown =
true;
1047 if (shouldSendArchive) {
1048 JAMI_DEBUG(
"[LinkDevice] SOURCE: Archive in message has encryption scheme '{}'",
1049 ctx->addDeviceCtx->authScheme);
1050 emitSignal<libjami::ConfigurationSignal::AddDeviceStateChanged>(ctx->accountId,
1052 static_cast<uint8_t
>(
1053 DeviceAuthState::IN_PROGRESS),
1055 shouldShutdown =
true;
1056 shouldSendMsg =
true;
1057 ctx->addDeviceCtx->archiveTransferredWithoutFailure =
true;
1058 toSend.set(PayloadKey::accData, ctx->addDeviceCtx->accData);
1060 if (shouldSendMsg) {
1061 JAMI_DEBUG(
"[LinkDevice] SOURCE: Sending msg to NEW:\n{}", toSend.formatMsg());
1062 msgpack::sbuffer buffer(UINT16_MAX);
1063 msgpack::pack(buffer, toSend);
1065 ctx->addDeviceCtx->channel->write(
reinterpret_cast<const unsigned char*
>(buffer.data()), buffer.size(), ec);
1068 return shouldShutdown ? std::make_error_code(std::errc::operation_canceled) :
std::error_code();
1071 if (ctx->addDeviceCtx->state == AuthDecodingState::HANDSHAKE) {
1072 ctx->addDeviceCtx->state = AuthDecodingState::EST;
1073 DeviceAuthInfo info;
1074 info.set(DeviceAuthInfo::peer_address, ctx->addDeviceCtx->channel->getRemoteAddress().toString(
true));
1075 emitSignal<libjami::ConfigurationSignal::AddDeviceStateChanged>(ctx->accountId,
1077 static_cast<uint8_t
>(
1078 DeviceAuthState::AUTHENTICATING),
1086ArchiveAccountManager::cancelAddDevice(uint32_t token)
1088 if (
auto ctx = authCtx_) {
1089 if (
ctx->token == token) {
1090 ctx->canceled =
true;
1091 if (
ctx->addDeviceCtx) {
1092 ctx->addDeviceCtx->state = AuthDecodingState::CANCELED;
1093 if (
ctx->addDeviceCtx->channel) {
1095 auto canceledMsg =
ctx->addDeviceCtx->createCanceledMsg();
1096 msgpack::sbuffer buffer(UINT16_MAX);
1097 msgpack::pack(buffer, canceledMsg);
1099 ctx->addDeviceCtx->channel->write(
reinterpret_cast<const unsigned char*
>(buffer.data()),
1102 ctx->addDeviceCtx->channel->shutdown();
1106 ctx->onFailure(AuthError::UNKNOWN,
"");
1115ArchiveAccountManager::confirmAddDevice(uint32_t token)
1117 if (
auto ctx = authCtx_) {
1118 if (
ctx->token == token &&
ctx->addDeviceCtx &&
ctx->addDeviceCtx->state == AuthDecodingState::EST) {
1119 dht::ThreadPool::io().run([
ctx] {
1120 ctx->addDeviceCtx->state = AuthDecodingState::AUTH;
1122 JAMI_DEBUG(
"[LinkDevice] SOURCE: Packing first message for NEW and switching to "
1124 ctx->addDeviceCtx->formattedAuthState());
1125 toSend.
set(PayloadKey::authScheme,
ctx->addDeviceCtx->authScheme);
1126 msgpack::sbuffer buffer(UINT16_MAX);
1127 msgpack::pack(buffer, toSend);
1129 ctx->addDeviceCtx->channel->write(
reinterpret_cast<const unsigned char*
>(buffer.data()),
1140ArchiveAccountManager::migrateAccount(AuthContext&
ctx)
1142 JAMI_WARN(
"[Auth] Account migration needed");
1145 archive = readArchive(
ctx.credentials->password_scheme,
ctx.credentials->password);
1147 JAMI_DBG(
"[Auth] Unable to load archive");
1148 ctx.onFailure(AuthError::INVALID_ARGUMENTS,
"");
1152 updateArchive(archive);
1154 if (updateCertificates(archive, ctx.credentials->updateIdentity)) {
1157 onArchiveLoaded(ctx, std::move(archive),
false);
1159 ctx.onFailure(AuthError::UNKNOWN,
"");
1164ArchiveAccountManager::onArchiveLoaded(AuthContext& ctx, AccountArchive&& a,
bool isLinkDevProtocol)
1167 dhtnet::fileutils::check_dir(path_, 0700);
1169 if (isLinkDevProtocol) {
1174 a.
save(fileutils::getFullPath(path_, archivePath_),
1175 ctx.linkDevCtx->authScheme,
1176 ctx.linkDevCtx->credentialsFromUser);
1182 a.
save(fileutils::getFullPath(path_, archivePath_),
1183 ctx.credentials ? ctx.credentials->password_scheme :
"",
1184 ctx.credentials ? ctx.credentials->
password :
"");
1187 if (not a.
id.second->isCA()) {
1188 JAMI_ERROR(
"[Account {}] [Auth] Attempting to sign a certificate with a non-CA.", accountId_);
1191 std::shared_ptr<dht::crypto::Certificate> deviceCertificate;
1192 std::unique_ptr<ContactList> contacts;
1193 auto usePreviousIdentity =
false;
1195 if (
auto oldId = ctx.credentials->updateIdentity.second) {
1196 contacts = std::make_unique<ContactList>(ctx.accountId, oldId, path_, onChange_);
1197 if (contacts->isValidAccountDevice(*oldId) && ctx.credentials->updateIdentity.first) {
1198 deviceCertificate = oldId;
1199 usePreviousIdentity =
true;
1200 JAMI_WARNING(
"[Account {}] [Auth] Using previously generated device certificate {}",
1202 deviceCertificate->getLongId());
1209 if (!deviceCertificate) {
1210 JAMI_WARNING(
"[Account {}] [Auth] Creating new device certificate", accountId_);
1211 auto request = ctx.request.get();
1212 if (not request->verify()) {
1213 JAMI_ERROR(
"[Account {}] [Auth] Invalid certificate request.", accountId_);
1214 ctx.onFailure(AuthError::INVALID_ARGUMENTS,
"");
1217 deviceCertificate = std::make_shared<dht::crypto::Certificate>(
1218 dht::crypto::Certificate::generate(*request, a.
id));
1219 JAMI_WARNING(
"[Account {}] [Auth] Created new device: {}", accountId_, deviceCertificate->getLongId());
1222 auto receipt = makeReceipt(a.
id, *deviceCertificate, ethAccount);
1223 auto receiptSignature = a.
id.first->sign(receipt.first);
1225 auto info = std::make_unique<AccountInfo>();
1226 auto pk = usePreviousIdentity ? ctx.credentials->updateIdentity.first : ctx.key.get();
1227 auto sharedPk = pk->getSharedPublicKey();
1228 info->identity.first = pk;
1229 info->identity.second = deviceCertificate;
1230 info->accountId = a.
id.second->getId().toString();
1231 info->devicePk = sharedPk;
1232 info->deviceId = info->devicePk->getLongId().toString();
1233 if (ctx.deviceName.empty())
1234 ctx.deviceName = info->deviceId.substr(8);
1237 contacts = std::make_unique<ContactList>(ctx.accountId, a.
id.second, path_, onChange_);
1239 info->contacts = std::move(contacts);
1240 info->contacts->setContacts(a.
contacts);
1241 info->contacts->foundAccountDevice(deviceCertificate, ctx.deviceName, clock::now());
1242 info->ethAccount = ethAccount;
1243 info->announce = std::move(receipt.second);
1244 ConversationModule::saveConvInfosToPath(path_, a.
conversations);
1246 info_ = std::move(info);
1248 ctx.onSuccess(*info_, std::move(a.
config), std::move(receipt.first), std::move(receiptSignature));
1251std::pair<std::vector<uint8_t>, dht::InfoHash>
1252ArchiveAccountManager::computeKeys(
const std::string& password,
const std::string& pin,
bool previous)
1255 auto now = std::chrono::duration_cast<std::chrono::seconds>(clock::now().time_since_epoch());
1256 auto tseed = now.count() / std::chrono::seconds(EXPORT_KEY_RENEWAL_TIME).count();
1259 std::ostringstream ss;
1260 ss << std::hex << tseed;
1261 auto tseed_str = ss.str();
1264 std::vector<uint8_t> salt_key;
1265 salt_key.reserve(pin.size() + tseed_str.size());
1266 salt_key.insert(salt_key.end(), pin.begin(), pin.end());
1267 salt_key.insert(salt_key.end(), tseed_str.begin(), tseed_str.end());
1268 auto key = dht::crypto::stretchKey(password, salt_key, 256 / 8);
1271 auto loc = dht::InfoHash::get(key);
1276std::pair<std::string, std::shared_ptr<dht::Value>>
1277ArchiveAccountManager::makeReceipt(
const dht::crypto::Identity&
id,
1278 const dht::crypto::Certificate& device,
1279 const std::string& ethAccount)
1281 JAMI_LOG(
"[Account {}] [Auth] Signing receipt for device {}", accountId_, device.getLongId());
1282 auto devId = device.getId();
1283 DeviceAnnouncement announcement;
1284 announcement.dev = devId;
1285 announcement.pk = device.getSharedPublicKey();
1286 dht::Value ann_val {announcement};
1287 ann_val.sign(*
id.first);
1289 auto packedAnnoucement = ann_val.getPacked();
1290 JAMI_LOG(
"[Account {}] [Auth] Device announcement size: {}", accountId_, packedAnnoucement.size());
1292 std::ostringstream is;
1293 is <<
"{\"id\":\"" <<
id.second->getId() <<
"\",\"dev\":\"" << devId <<
"\",\"eth\":\"" << ethAccount
1294 <<
"\",\"announce\":\"" << base64::encode(packedAnnoucement) <<
"\"}";
1297 return {is.str(), std::make_shared<dht::Value>(std::move(ann_val))};
1301ArchiveAccountManager::needsMigration(
const std::string& accountId,
const dht::crypto::Identity&
id)
1305 auto cert =
id.second->issuer;
1307 if (not cert->isCA()) {
1308 JAMI_WARNING(
"[Account {}] [Auth] certificate {} is not a CA, needs update.", accountId, cert->getId());
1311 if (cert->getExpiration() < clock::now()) {
1312 JAMI_WARNING(
"[Account {}] [Auth] certificate {} is expired, needs update.", accountId, cert->getId());
1315 cert = cert->issuer;
1321ArchiveAccountManager::syncDevices()
1323 JAMI_LOG(
"[Account {}] Building device sync from {}", accountId_, info_->deviceId);
1324 onSyncData_(info_->contacts->getSyncData());
1328ArchiveAccountManager::readArchive(std::string_view scheme,
const std::string& pwd)
const
1330 JAMI_LOG(
"[Account {}] [Auth] Reading account archive", accountId_);
1331 return AccountArchive(fileutils::getFullPath(path_, archivePath_), scheme, pwd);
1335ArchiveAccountManager::updateArchive(AccountArchive& archive)
const
1340 static const auto filtered_keys = {Ringtone::PATH,
1344 Conf::CONFIG_DHT_PORT,
1352 static const auto encoded_keys = {TLS::CA_LIST_FILE, TLS::CERTIFICATE_FILE, TLS::PRIVATE_KEY_FILE};
1354 JAMI_LOG(
"[Account {}] [Auth] Building account archive", accountId_);
1355 for (
const auto& it : onExportConfig_()) {
1357 if (std::any_of(std::begin(filtered_keys), std::end(filtered_keys), [&](
const auto& key) {
1358 return key == it.first;
1363 if (std::any_of(std::begin(encoded_keys), std::end(encoded_keys), [&](
const auto& key) {
1364 return key == it.first;
1367 archive.config.emplace(it.first, base64::encode(fileutils::loadFile(it.second)));
1371 archive.config[it.first] = it.second;
1375 archive.contacts = info_->contacts->getContacts();
1377 archive.conversations = ConversationModule::convInfosFromPath(path_);
1378 archive.conversationsRequests = ConversationModule::convRequestsFromPath(path_);
1383ArchiveAccountManager::saveArchive(AccountArchive& archive, std::string_view scheme,
const std::string& pwd)
1386 updateArchive(archive);
1387 if (archivePath_.empty())
1388 archivePath_ =
"export.gz";
1389 archive.save(fileutils::getFullPath(path_, archivePath_), scheme, pwd);
1390 }
catch (
const std::runtime_error& ex) {
1391 JAMI_ERROR(
"[Account {}] [Auth] Unable to export archive: {}", accountId_, ex.what());
1397ArchiveAccountManager::changePassword(
const std::string& password_old,
const std::string& password_new)
1400 auto path = fileutils::getFullPath(path_, archivePath_);
1401 AccountArchive(path, fileutils::ARCHIVE_AUTH_SCHEME_PASSWORD, password_old)
1402 .
save(path, fileutils::ARCHIVE_AUTH_SCHEME_PASSWORD, password_new);
1404 }
catch (
const std::exception&) {
1410ArchiveAccountManager::getPasswordKey(
const std::string& password)
1413 auto data = dhtnet::fileutils::loadFile(fileutils::getFullPath(path_, archivePath_));
1415 auto key = dht::crypto::aesGetKey(data, password);
1416 auto decrypted = dht::crypto::aesDecrypt(dht::crypto::aesGetEncrypted(data), key);
1418 }
catch (
const std::exception& e) {
1419 JAMI_ERROR(
"[Account {}] Error loading archive: {}", accountId_, e.what());
1425ArchiveAccountManager::revokeDevice(
const std::string& device,
1426 std::string_view scheme,
1427 const std::string& password,
1430 auto fa = dht::ThreadPool::computation().getShared<
AccountArchive>(
1431 [
this, scheme = std::string(scheme), password] {
return readArchive(scheme, password); });
1433 [fa = std::move(fa), scheme = std::string(scheme), password, device, cb, w = weak()](
1434 const std::shared_ptr<dht::crypto::Certificate>& crt)
mutable {
1436 cb(RevokeDeviceResult::ERROR_NETWORK);
1439 auto this_ = w.lock();
1442 this_->info_->contacts->foundAccountDevice(crt);
1447 cb(RevokeDeviceResult::ERROR_CREDENTIALS);
1452 a.
revoked = std::make_shared<
decltype(a.
revoked)::element_type>();
1456 this_->certStore().pinRevocationList(a.
id.second->getId().toString(), a.
revoked);
1457 this_->certStore().loadRevocations(*a.
id.second);
1460 auto h = a.
id.second->getId();
1461 this_->dht_->put(h, a.
revoked, dht::DoneCallback {}, {},
true);
1463 this_->saveArchive(a, scheme, password);
1464 this_->info_->contacts->removeAccountDevice(crt->getLongId());
1465 cb(RevokeDeviceResult::SUCCESS);
1466 this_->syncDevices();
1472ArchiveAccountManager::exportArchive(
const std::string& destinationPath,
1473 std::string_view scheme,
1474 const std::string& password)
1479 updateArchive(archive);
1480 auto archivePath = fileutils::getFullPath(path_, archivePath_);
1481 if (!archive.
save(archivePath, scheme, password))
1486 std::filesystem::copy_file(archivePath, destinationPath, std::filesystem::copy_options::overwrite_existing, ec);
1488 }
catch (
const std::runtime_error& ex) {
1489 JAMI_ERR(
"[Auth] Unable to export archive: %s", ex.what());
1492 JAMI_ERR(
"[Auth] Unable to export archive: Unable to read archive");
1498ArchiveAccountManager::isPasswordValid(
const std::string& password)
1501 readArchive(fileutils::ARCHIVE_AUTH_SCHEME_PASSWORD, password);
1509ArchiveAccountManager::registerName(
const std::string& name,
1510 std::string_view scheme,
1511 const std::string& password,
1514 std::string signedName;
1515 auto nameLowercase {name};
1516 std::transform(nameLowercase.begin(), nameLowercase.end(), nameLowercase.begin(), ::tolower);
1517 std::string publickey;
1518 std::string accountId;
1519 std::string ethAccount;
1522 auto archive = readArchive(scheme, password);
1523 auto privateKey = archive.id.first;
1524 const auto& pk = privateKey->getPublicKey();
1525 publickey = pk.toString();
1526 accountId = pk.getId().toString();
1527 signedName = base64::encode(privateKey->sign(std::vector<uint8_t>(nameLowercase.begin(), nameLowercase.end())));
1529 }
catch (
const std::exception& e) {
1531 cb(NameDirectory::RegistrationResponse::invalidCredentials, name);
1535 nameDir_.get().registerName(accountId, nameLowercase, ethAccount, cb, signedName, publickey);
Account specific keys/constants that must be shared in daemon and clients.
Simple class that represents a "key pair".
static KeyPair create()
Create a new, randomly generated object.
Address const & address() const
Retrieve the associated address of the public key.
NameDirectory::RegistrationCallback RegistrationCallback
const std::string accountId_
OnChangeCallback onChange_
CertRequest buildRequest(PrivateKey fDeviceKey)
std::shared_future< std::shared_ptr< dht::crypto::PrivateKey > > PrivateKey
std::function< void(RevokeDeviceResult)> RevokeDeviceCallback
std::function< void(AuthError error, const std::string &message)> AuthFailureCallback
std::function< void(const AccountInfo &info, const std::map< std::string, std::string > &config, std::string &&receipt, std::vector< uint8_t > &&receipt_signature)> AuthSuccessCallback
void initAuthentication(PrivateKey request, std::string deviceName, std::unique_ptr< AccountCredentials > credentials, AuthSuccessCallback onSuccess, AuthFailureCallback onFailure, const OnChangeCallback &onChange) override
Manages channels for syncing informations.
void connect(const DeviceId &deviceId, const std::string &name, ConnectCb &&cb, const std::string &connectionType="", bool forceNewConnection=false) override
Ask for a new sync channel.
#define JAMI_ERROR(formatstr,...)
#define JAMI_DEBUG(formatstr,...)
#define JAMI_WARNING(formatstr,...)
#define JAMI_LOG(formatstr,...)
static constexpr auto stateMsg
static constexpr auto accData
static constexpr auto password
static constexpr auto passwordCorrect
static constexpr auto canRetry
static constexpr auto authScheme
static constexpr std::string_view toString(AuthDecodingState state)
void emitSignal(Args... args)
constexpr auto CHANNEL_SCHEME
const constexpr auto EXPORT_KEY_RENEWAL_TIME
constexpr auto AUTH_URI_SCHEME
constexpr auto OP_TIMEOUT
static constexpr const char ARCHIVE_HAS_PASSWORD[]
Crypto material contained in the archive, not persisted in the account configuration.
bool save(const std::filesystem::path &path, std::string_view scheme, const std::string &password) const
Save archive to file, optionally encrypted with provided password.
std::map< dht::InfoHash, Contact > contacts
Contacts.
std::map< std::string, ConversationRequest > conversationsRequests
std::shared_ptr< dht::crypto::RevocationList > revoked
Revoked devices.
std::shared_ptr< dht::crypto::PrivateKey > ca_key
Generated CA key (for self-signed certificates)
dht::crypto::Identity id
Account main private key and certificate chain.
std::map< std::string, ConvInfo > conversations
std::vector< uint8_t > eth_key
Ethereum private key.
std::map< std::string, std::string > config
Account configuration.
AuthMsg createCanceledMsg() const
std::string_view authScheme
AddDeviceContext(std::shared_ptr< dhtnet::ChannelSocket > c)
std::shared_ptr< dhtnet::ChannelSocket > channel
void set(std::string_view key, std::string_view value)
std::map< std::string, std::string > payload
auto at(std::string_view key) const
auto find(std::string_view key) const
std::map< std::string, std::string > Map
static DeviceAuthInfo createError(Error err)
DeviceAuthInfo(const Map &map)
void set(std::string_view key, std::string_view value)
DeviceAuthInfo(Map &&map)
constexpr std::string_view formattedAuthState() const
DeviceAuthInfo::Error getErrorState() const
bool handleTimeoutMessage(const AuthMsg &msg)
bool handleCanceledMessage(const AuthMsg &msg)
DeviceContextBase(uint64_t operationId, AuthDecodingState initialState)
LinkDeviceContext(const std::shared_ptr< dhtnet::ConnectionManager::Config > &config)
dht::crypto::Identity tmpId
dhtnet::ConnectionManager tempConnMgr
std::shared_ptr< dhtnet::ChannelSocket > channel