blob: b8b51b56c012200a26f5afe6581a721828199c15 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/host/remoting_register_support_host_request.h"
#include "base/strings/stringize_macros.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "remoting/base/oauth_token_getter.h"
#include "remoting/base/protobuf_http_client.h"
#include "remoting/base/protobuf_http_request.h"
#include "remoting/base/protobuf_http_request_config.h"
#include "remoting/base/protobuf_http_status.h"
#include "remoting/base/service_urls.h"
#include "remoting/host/host_details.h"
#include "remoting/proto/remoting/v1/remote_support_host_messages.pb.h"
#include "remoting/signaling/signaling_address.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace remoting {
namespace {
constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
net::DefineNetworkTrafficAnnotation(
"remoting_register_support_host_request",
R"(
semantics {
sender: "Chrome Remote Desktop"
description:
"Request used by Chrome Remote Desktop to register a new remote "
"support host."
trigger:
"User requests for remote assistance using Chrome Remote Desktop."
data:
"The user's OAuth token for Chrome Remote Desktop (CRD) and CRD "
"host information such as CRD host public key, host version, and "
"OS version."
destination: GOOGLE_OWNED_SERVICE
}
policy {
cookies_allowed: NO
setting:
"This request cannot be stopped in settings, but will not be sent "
"if the user does not use Chrome Remote Desktop."
policy_exception_justification:
"Not implemented."
})");
constexpr char kRegisterSupportHostPath[] =
"/v1/remotesupport:registersupporthost";
protocol::ErrorCode MapError(ProtobufHttpStatus::Code status_code) {
switch (status_code) {
case ProtobufHttpStatus::Code::OK:
return protocol::ErrorCode::OK;
case ProtobufHttpStatus::Code::DEADLINE_EXCEEDED:
return protocol::ErrorCode::SIGNALING_TIMEOUT;
case ProtobufHttpStatus::Code::PERMISSION_DENIED:
case ProtobufHttpStatus::Code::UNAUTHENTICATED:
return protocol::ErrorCode::AUTHENTICATION_FAILED;
default:
return protocol::ErrorCode::SIGNALING_ERROR;
}
}
} // namespace
class RemotingRegisterSupportHostRequest::RegisterSupportHostClientImpl final
: public RegisterSupportHostClient {
public:
RegisterSupportHostClientImpl(
OAuthTokenGetter* token_getter,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
RegisterSupportHostClientImpl(const RegisterSupportHostClientImpl&) = delete;
RegisterSupportHostClientImpl& operator=(
const RegisterSupportHostClientImpl&) = delete;
~RegisterSupportHostClientImpl() override;
void RegisterSupportHost(
std::unique_ptr<apis::v1::RegisterSupportHostRequest> request,
RegisterSupportHostResponseCallback callback) override;
void CancelPendingRequests() override;
private:
ProtobufHttpClient http_client_;
};
RemotingRegisterSupportHostRequest::RegisterSupportHostClientImpl::
RegisterSupportHostClientImpl(
OAuthTokenGetter* token_getter,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
: http_client_(ServiceUrls::GetInstance()->remoting_server_endpoint(),
token_getter,
url_loader_factory) {}
RemotingRegisterSupportHostRequest::RegisterSupportHostClientImpl::
~RegisterSupportHostClientImpl() = default;
void RemotingRegisterSupportHostRequest::RegisterSupportHostClientImpl::
RegisterSupportHost(
std::unique_ptr<apis::v1::RegisterSupportHostRequest> request,
RegisterSupportHostResponseCallback callback) {
auto request_config =
std::make_unique<ProtobufHttpRequestConfig>(kTrafficAnnotation);
request_config->path = kRegisterSupportHostPath;
request_config->request_message = std::move(request);
auto http_request =
std::make_unique<ProtobufHttpRequest>(std::move(request_config));
http_request->SetResponseCallback(std::move(callback));
http_client_.ExecuteRequest(std::move(http_request));
}
void RemotingRegisterSupportHostRequest::RegisterSupportHostClientImpl::
CancelPendingRequests() {
http_client_.CancelPendingRequests();
}
// End of RegisterSupportHostClientImpl.
RemotingRegisterSupportHostRequest::RemotingRegisterSupportHostRequest(
std::unique_ptr<OAuthTokenGetter> token_getter,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
: token_getter_(std::move(token_getter)),
register_host_client_(std::make_unique<RegisterSupportHostClientImpl>(
token_getter_.get(),
url_loader_factory)) {}
RemotingRegisterSupportHostRequest::~RemotingRegisterSupportHostRequest() {
if (signal_strategy_) {
signal_strategy_->RemoveListener(this);
}
}
void RemotingRegisterSupportHostRequest::StartRequest(
SignalStrategy* signal_strategy,
scoped_refptr<RsaKeyPair> key_pair,
RegisterCallback callback) {
DCHECK_EQ(State::NOT_STARTED, state_);
DCHECK(signal_strategy);
DCHECK(key_pair);
DCHECK(callback);
signal_strategy_ = signal_strategy;
key_pair_ = key_pair;
callback_ = std::move(callback);
signal_strategy_->AddListener(this);
}
void RemotingRegisterSupportHostRequest::OnSignalStrategyStateChange(
SignalStrategy::State state) {
switch (state) {
case SignalStrategy::State::CONNECTED:
RegisterHost();
break;
case SignalStrategy::State::DISCONNECTED:
RunCallback({}, {}, protocol::ErrorCode::SIGNALING_ERROR);
break;
default:
// Do nothing.
break;
}
}
bool RemotingRegisterSupportHostRequest::OnSignalStrategyIncomingStanza(
const jingle_xmpp::XmlElement* stanza) {
return false;
}
void RemotingRegisterSupportHostRequest::RegisterHost() {
DCHECK_EQ(SignalStrategy::CONNECTED, signal_strategy_->GetState());
if (state_ != State::NOT_STARTED) {
return;
}
state_ = State::REGISTERING;
auto request = std::make_unique<apis::v1::RegisterSupportHostRequest>();
request->set_public_key(key_pair_->GetPublicKey());
request->set_tachyon_id(signal_strategy_->GetLocalAddress().id());
request->set_host_version(STRINGIZE(VERSION));
request->set_host_os_name(GetHostOperatingSystemName());
request->set_host_os_version(GetHostOperatingSystemVersion());
register_host_client_->RegisterSupportHost(
std::move(request),
base::BindOnce(&RemotingRegisterSupportHostRequest::OnRegisterHostResult,
base::Unretained(this)));
}
void RemotingRegisterSupportHostRequest::OnRegisterHostResult(
const ProtobufHttpStatus& status,
std::unique_ptr<apis::v1::RegisterSupportHostResponse> response) {
if (!status.ok()) {
state_ = State::NOT_STARTED;
RunCallback({}, {}, MapError(status.error_code()));
return;
}
state_ = State::REGISTERED;
base::TimeDelta lifetime =
base::Seconds(response->support_id_lifetime_seconds());
RunCallback(response->support_id(), lifetime, protocol::ErrorCode::OK);
}
void RemotingRegisterSupportHostRequest::RunCallback(
const std::string& support_id,
base::TimeDelta lifetime,
protocol::ErrorCode error_code) {
if (!callback_) {
// Callback has already been run, so just return.
return;
}
// Cleanup state before calling the callback.
register_host_client_->CancelPendingRequests();
signal_strategy_->RemoveListener(this);
signal_strategy_ = nullptr;
std::move(callback_).Run(support_id, lifetime, error_code);
}
} // namespace remoting