blob: b9fca95397b9e94c87e9dc65d759f2fe0a69ca3c [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/signaling/corp_messaging_client.h"
#include <utility>
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/time/time.h"
#include "base/uuid.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "remoting/base/http_status.h"
#include "remoting/base/internal_headers.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_stream_request.h"
#include "remoting/base/service_urls.h"
#include "remoting/signaling/corp_message_channel_strategy.h"
#include "remoting/signaling/message_channel.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace remoting {
namespace {
constexpr net::NetworkTrafficAnnotationTag kReceiveMessagesTrafficAnnotation =
net::DefineNetworkTrafficAnnotation(
"corp_messaging_client_receive_client_messages",
R"(
semantics {
sender: "Chrome Remote Desktop"
description:
"Receives signaling messages from the Chrome Remote Desktop peer "
"(a Chrome Remote Desktop client) via a Chrome Remote Desktop server "
"when a user initiates the connection process."
trigger:
"Starting the Chrome Remote Desktop agent on a Google Corp machine."
user_data {
type: NONE
}
data: "No user data is provided in the request."
destination: GOOGLE_OWNED_SERVICE
internal {
contacts { owners: "//remoting/OWNERS" }
}
last_reviewed: "2025-09-05"
}
policy {
cookies_allowed: NO
setting:
"This request cannot be stopped in settings, but will not be sent if "
"the user does not configure a Google Corp machine for remote access."
policy_exception_justification:
"Not implemented."
})");
constexpr net::NetworkTrafficAnnotationTag kSendMessageTrafficAnnotation =
net::DefineNetworkTrafficAnnotation(
"corp_messaging_client_send_host_message",
R"(
semantics {
sender: "Chrome Remote Desktop"
description:
"Sends signaling messages to the Chrome Remote Desktop peer "
"(a Chrome Remote Desktop client) via a Chrome Remote Desktop server "
"when a user initiates the connection process."
trigger:
"A remote user begins the connection process to a Google Corp machine."
user_data {
type: NONE
}
data: "No user data is provided in the request."
destination: GOOGLE_OWNED_SERVICE
internal {
contacts { owners: "//remoting/OWNERS" }
}
last_reviewed: "2025-09-05"
}
policy {
cookies_allowed: NO
setting:
"This request cannot be stopped in settings, but will not be sent if "
"the user does not configure a Google Corp machine for remote access."
policy_exception_justification:
"Not implemented."
})");
} // namespace
CorpMessagingClient::CorpMessagingClient(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
std::unique_ptr<net::ClientCertStore> client_cert_store)
: client_(std::make_unique<ProtobufHttpClient>(
ServiceUrls::GetInstance()->remoting_corp_endpoint(),
/*token_getter=*/nullptr,
url_loader_factory,
std::move(client_cert_store))) {
auto channel_strategy = std::make_unique<CorpMessageChannelStrategy>();
channel_strategy->Initialize(
base::BindRepeating(&CorpMessagingClient::OpenReceiveMessagesStream,
base::Unretained(this)),
base::BindRepeating(&CorpMessagingClient::OnMessageReceived,
base::Unretained(this)));
message_channel_ = std::make_unique<MessageChannel>(
std::move(channel_strategy), /*signaling_tracker=*/nullptr);
}
CorpMessagingClient::~CorpMessagingClient() = default;
base::CallbackListSubscription CorpMessagingClient::RegisterMessageCallback(
const MessageCallback& callback) {
return callback_list_.Add(callback);
}
void CorpMessagingClient::SendMessage(
const internal::EndpointIdStruct& destination_id,
const std::string& payload,
StatusCallback on_done) {
internal::SendHostMessageRequestStruct request;
request.destination_id = destination_id;
request.simple_message.message_id =
base::Uuid::GenerateRandomV4().AsLowercaseString();
request.simple_message.payload = payload;
request.simple_message.create_time = base::Time::Now();
// SendHostMessage is non-idempotent (potentially duplicate messages will be
// sent), so retries may not be safe.
ExecuteRequest(
kSendMessageTrafficAnnotation,
std::string(internal::GetSendHostMessagePath()),
/*enable_retries=*/false, internal::GetSendHostMessageRequest(request),
&CorpMessagingClient::OnSendMessageResponse, std::move(on_done));
}
void CorpMessagingClient::StartReceivingMessages(base::OnceClosure on_ready,
StatusCallback on_closed) {
message_channel_->StartReceivingMessages(std::move(on_ready),
std::move(on_closed));
}
void CorpMessagingClient::StopReceivingMessages() {
message_channel_->StopReceivingMessages();
}
bool CorpMessagingClient::IsReceivingMessages() const {
return message_channel_->IsReceivingMessages();
}
template <typename CallbackFunctor>
void CorpMessagingClient::ExecuteRequest(
const net::NetworkTrafficAnnotationTag& tag,
const std::string& path,
bool enable_retries,
std::unique_ptr<google::protobuf::MessageLite> request,
CallbackFunctor callback_functor,
StatusCallback on_done) {
auto config = std::make_unique<ProtobufHttpRequestConfig>(tag);
config->request_message = std::move(request);
config->path = path;
if (enable_retries) {
config->UseSimpleRetryPolicy();
}
config->authenticated = false;
config->api_key = internal::GetRemotingCorpApiKey();
config->provide_certificate = true;
auto http_request = std::make_unique<ProtobufHttpRequest>(std::move(config));
http_request->SetResponseCallback(base::BindOnce(
callback_functor, base::Unretained(this), std::move(on_done)));
client_->ExecuteRequest(std::move(http_request));
}
void CorpMessagingClient::OnSendMessageResponse(
StatusCallback on_done,
const HttpStatus& status,
std::unique_ptr<internal::SendHostMessageResponse> response) {
std::move(on_done).Run(status);
}
std::unique_ptr<ScopedProtobufHttpRequest>
CorpMessagingClient::OpenReceiveMessagesStream(
base::OnceClosure on_channel_ready,
const CorpMessageChannelStrategy::MessageReceivedCallback& on_message,
base::OnceCallback<void(const HttpStatus&)> on_channel_closed) {
auto config = std::make_unique<ProtobufHttpRequestConfig>(
kReceiveMessagesTrafficAnnotation);
config->request_message = internal::GetReceiveClientMessagesRequest({});
config->path = internal::GetReceiveClientMessagesPath();
config->authenticated = false;
config->api_key = internal::GetRemotingCorpApiKey();
config->provide_certificate = true;
auto stream_request =
std::make_unique<ProtobufHttpStreamRequest>(std::move(config));
stream_request->SetStreamReadyCallback(std::move(on_channel_ready));
stream_request->SetMessageCallback(base::BindRepeating(
[](CorpMessageChannelStrategy::MessageReceivedCallback callback,
std::unique_ptr<internal::ReceiveClientMessagesResponse> response) {
std::move(callback).Run(
internal::GetReceiveClientMessagesResponseStruct(*response));
},
on_message));
stream_request->SetStreamClosedCallback(std::move(on_channel_closed));
auto request_holder = stream_request->CreateScopedRequest();
client_->ExecuteRequest(std::move(stream_request));
return request_holder;
}
void CorpMessagingClient::OnMessageReceived(
const internal::SimpleMessageStruct& message) {
callback_list_.Notify(message);
}
} // namespace remoting