me2me_native_messaging_host.cc 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  1. // Copyright 2013 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "remoting/host/setup/me2me_native_messaging_host.h"
  5. #include <cstdint>
  6. #include <memory>
  7. #include <string>
  8. #include <utility>
  9. #include "base/bind.h"
  10. #include "base/callback.h"
  11. #include "base/command_line.h"
  12. #include "base/json/json_reader.h"
  13. #include "base/json/json_writer.h"
  14. #include "base/logging.h"
  15. #include "base/strings/stringize_macros.h"
  16. #include "base/task/single_thread_task_runner.h"
  17. #include "base/time/time.h"
  18. #include "base/values.h"
  19. #include "build/build_config.h"
  20. #include "google_apis/gaia/gaia_oauth_client.h"
  21. #include "google_apis/google_api_keys.h"
  22. #include "net/base/network_interfaces.h"
  23. #include "remoting/base/auto_thread_task_runner.h"
  24. #include "remoting/base/oauth_client.h"
  25. #include "remoting/base/rsa_key_pair.h"
  26. #include "remoting/host/chromoting_host_context.h"
  27. #include "remoting/host/native_messaging/log_message_handler.h"
  28. #include "remoting/host/pin_hash.h"
  29. #include "remoting/protocol/pairing_registry.h"
  30. #include "third_party/abseil-cpp/absl/types/optional.h"
  31. #if BUILDFLAG(IS_WIN)
  32. #include "remoting/host/win/elevated_native_messaging_host.h"
  33. #endif // BUILDFLAG(IS_WIN)
  34. namespace {
  35. #if BUILDFLAG(IS_WIN)
  36. const int kElevatedHostTimeoutSeconds = 300;
  37. #endif // BUILDFLAG(IS_WIN)
  38. // Features supported in addition to the base protocol.
  39. const char* kSupportedFeatures[] = {
  40. "pairingRegistry",
  41. "oauthClient",
  42. "getRefreshTokenFromAuthCode",
  43. #if BUILDFLAG(IS_APPLE)
  44. "it2mePermissionCheck",
  45. #endif // BUILDFLAG(IS_APPLE)
  46. };
  47. // Helper to extract the "config" part of a message as a base::Value::Dict.
  48. // Returns nullptr on failure, and logs an error message.
  49. absl::optional<base::Value::Dict> ConfigDictionaryFromMessage(
  50. base::Value::Dict message) {
  51. if (base::Value::Dict* config_dict = message.FindDict("config")) {
  52. return std::move(*config_dict);
  53. }
  54. return absl::nullopt;
  55. }
  56. } // namespace
  57. namespace remoting {
  58. Me2MeNativeMessagingHost::Me2MeNativeMessagingHost(
  59. bool needs_elevation,
  60. intptr_t parent_window_handle,
  61. std::unique_ptr<ChromotingHostContext> host_context,
  62. scoped_refptr<DaemonController> daemon_controller,
  63. scoped_refptr<protocol::PairingRegistry> pairing_registry,
  64. std::unique_ptr<OAuthClient> oauth_client)
  65. : needs_elevation_(needs_elevation),
  66. #if BUILDFLAG(IS_WIN)
  67. parent_window_handle_(parent_window_handle),
  68. #endif
  69. host_context_(std::move(host_context)),
  70. daemon_controller_(daemon_controller),
  71. pairing_registry_(pairing_registry),
  72. oauth_client_(std::move(oauth_client)) {
  73. weak_ptr_ = weak_factory_.GetWeakPtr();
  74. }
  75. Me2MeNativeMessagingHost::~Me2MeNativeMessagingHost() {
  76. DCHECK(task_runner()->BelongsToCurrentThread());
  77. }
  78. void Me2MeNativeMessagingHost::OnMessage(const std::string& message) {
  79. DCHECK(task_runner()->BelongsToCurrentThread());
  80. base::Value::Dict response;
  81. absl::optional<base::Value> message_value = base::JSONReader::Read(message);
  82. if (!message_value || !message_value->is_dict()) {
  83. OnError("Received a message that's not a dictionary.");
  84. return;
  85. }
  86. base::Value::Dict& message_dict = message_value->GetDict();
  87. // If the client supplies an ID, it will expect it in the response. This
  88. // might be a string or a number, so cope with both.
  89. if (const base::Value* id = message_dict.Find("id"))
  90. response.Set("id", id->Clone());
  91. const std::string* type = message_dict.FindString("type");
  92. if (!type) {
  93. OnError("'type' not found");
  94. return;
  95. }
  96. response.Set("type", *type + "Response");
  97. if (*type == "hello") {
  98. ProcessHello(std::move(message_dict), std::move(response));
  99. } else if (*type == "clearPairedClients") {
  100. ProcessClearPairedClients(std::move(message_dict), std::move(response));
  101. } else if (*type == "deletePairedClient") {
  102. ProcessDeletePairedClient(std::move(message_dict), std::move(response));
  103. } else if (*type == "getHostName") {
  104. ProcessGetHostName(std::move(message_dict), std::move(response));
  105. } else if (*type == "getPinHash") {
  106. ProcessGetPinHash(std::move(message_dict), std::move(response));
  107. } else if (*type == "generateKeyPair") {
  108. ProcessGenerateKeyPair(std::move(message_dict), std::move(response));
  109. } else if (*type == "updateDaemonConfig") {
  110. ProcessUpdateDaemonConfig(std::move(message_dict), std::move(response));
  111. } else if (*type == "getDaemonConfig") {
  112. ProcessGetDaemonConfig(std::move(message_dict), std::move(response));
  113. } else if (*type == "getPairedClients") {
  114. ProcessGetPairedClients(std::move(message_dict), std::move(response));
  115. } else if (*type == "getUsageStatsConsent") {
  116. ProcessGetUsageStatsConsent(std::move(message_dict), std::move(response));
  117. } else if (*type == "startDaemon") {
  118. ProcessStartDaemon(std::move(message_dict), std::move(response));
  119. } else if (*type == "stopDaemon") {
  120. ProcessStopDaemon(std::move(message_dict), std::move(response));
  121. } else if (*type == "getDaemonState") {
  122. ProcessGetDaemonState(std::move(message_dict), std::move(response));
  123. } else if (*type == "getHostClientId") {
  124. ProcessGetHostClientId(std::move(message_dict), std::move(response));
  125. } else if (*type == "getCredentialsFromAuthCode") {
  126. ProcessGetCredentialsFromAuthCode(
  127. std::move(message_dict), std::move(response), true);
  128. } else if (*type == "getRefreshTokenFromAuthCode") {
  129. ProcessGetCredentialsFromAuthCode(
  130. std::move(message_dict), std::move(response), false);
  131. } else if (*type == "it2mePermissionCheck") {
  132. ProcessIt2mePermissionCheck(std::move(message_dict), std::move(response));
  133. } else {
  134. OnError("Unsupported request type: " + *type);
  135. }
  136. }
  137. void Me2MeNativeMessagingHost::Start(Client* client) {
  138. DCHECK(task_runner()->BelongsToCurrentThread());
  139. client_ = client;
  140. log_message_handler_ =
  141. std::make_unique<LogMessageHandler>(base::BindRepeating(
  142. &Me2MeNativeMessagingHost::SendMessageToClient, weak_ptr_));
  143. }
  144. scoped_refptr<base::SingleThreadTaskRunner>
  145. Me2MeNativeMessagingHost::task_runner() const {
  146. return host_context_->ui_task_runner();
  147. }
  148. void Me2MeNativeMessagingHost::ProcessHello(base::Value::Dict message,
  149. base::Value::Dict response) {
  150. DCHECK(task_runner()->BelongsToCurrentThread());
  151. response.Set("version", STRINGIZE(VERSION));
  152. base::Value::List supported_features_list;
  153. for (const char* feature : kSupportedFeatures) {
  154. supported_features_list.Append(feature);
  155. }
  156. response.Set("supportedFeatures", std::move(supported_features_list));
  157. SendMessageToClient(std::move(response));
  158. }
  159. void Me2MeNativeMessagingHost::ProcessClearPairedClients(
  160. base::Value::Dict message,
  161. base::Value::Dict response) {
  162. DCHECK(task_runner()->BelongsToCurrentThread());
  163. if (needs_elevation_) {
  164. if (DelegateToElevatedHost(std::move(message)) != DELEGATION_SUCCESS) {
  165. SendBooleanResult(std::move(response), false);
  166. }
  167. return;
  168. }
  169. if (pairing_registry_.get()) {
  170. pairing_registry_->ClearAllPairings(
  171. base::BindOnce(&Me2MeNativeMessagingHost::SendBooleanResult, weak_ptr_,
  172. std::move(response)));
  173. } else {
  174. SendBooleanResult(std::move(response), false);
  175. }
  176. }
  177. void Me2MeNativeMessagingHost::ProcessDeletePairedClient(
  178. base::Value::Dict message,
  179. base::Value::Dict response) {
  180. DCHECK(task_runner()->BelongsToCurrentThread());
  181. if (needs_elevation_) {
  182. if (DelegateToElevatedHost(std::move(message)) != DELEGATION_SUCCESS) {
  183. SendBooleanResult(std::move(response), false);
  184. }
  185. return;
  186. }
  187. std::string* client_id =
  188. message.FindString(protocol::PairingRegistry::kClientIdKey);
  189. if (!client_id) {
  190. OnError("'" + std::string(protocol::PairingRegistry::kClientIdKey) +
  191. "' string not found.");
  192. return;
  193. }
  194. if (pairing_registry_.get()) {
  195. pairing_registry_->DeletePairing(
  196. std::move(*client_id),
  197. base::BindOnce(&Me2MeNativeMessagingHost::SendBooleanResult, weak_ptr_,
  198. std::move(response)));
  199. } else {
  200. SendBooleanResult(std::move(response), false);
  201. }
  202. }
  203. void Me2MeNativeMessagingHost::ProcessGetHostName(base::Value::Dict message,
  204. base::Value::Dict response) {
  205. DCHECK(task_runner()->BelongsToCurrentThread());
  206. response.Set("hostname", net::GetHostName());
  207. SendMessageToClient(std::move(response));
  208. }
  209. void Me2MeNativeMessagingHost::ProcessGetPinHash(base::Value::Dict message,
  210. base::Value::Dict response) {
  211. DCHECK(task_runner()->BelongsToCurrentThread());
  212. std::string* host_id = message.FindString("hostId");
  213. if (!host_id) {
  214. std::string message_json;
  215. base::JSONWriter::Write(message, &message_json);
  216. OnError("'hostId' not found: " + message_json);
  217. return;
  218. }
  219. std::string* pin = message.FindString("pin");
  220. if (!pin) {
  221. std::string message_json;
  222. base::JSONWriter::Write(message, &message_json);
  223. OnError("'pin' not found: " + message_json);
  224. return;
  225. }
  226. response.Set("hash", MakeHostPinHash(std::move(*host_id), std::move(*pin)));
  227. SendMessageToClient(std::move(response));
  228. }
  229. void Me2MeNativeMessagingHost::ProcessGenerateKeyPair(
  230. base::Value::Dict message,
  231. base::Value::Dict response) {
  232. DCHECK(task_runner()->BelongsToCurrentThread());
  233. scoped_refptr<RsaKeyPair> key_pair = RsaKeyPair::Generate();
  234. response.Set("privateKey", key_pair->ToString());
  235. response.Set("publicKey", key_pair->GetPublicKey());
  236. SendMessageToClient(std::move(response));
  237. }
  238. void Me2MeNativeMessagingHost::ProcessUpdateDaemonConfig(
  239. base::Value::Dict message,
  240. base::Value::Dict response) {
  241. DCHECK(task_runner()->BelongsToCurrentThread());
  242. if (needs_elevation_) {
  243. DelegationResult result = DelegateToElevatedHost(std::move(message));
  244. switch (result) {
  245. case DELEGATION_SUCCESS:
  246. return; // Result will be returned by elevated host.
  247. case DELEGATION_CANCELLED:
  248. SendAsyncResult(std::move(response),
  249. DaemonController::RESULT_CANCELLED);
  250. return;
  251. default:
  252. SendAsyncResult(std::move(response), DaemonController::RESULT_FAILED);
  253. return;
  254. }
  255. }
  256. absl::optional<base::Value::Dict> config_dict =
  257. ConfigDictionaryFromMessage(std::move(message));
  258. if (!config_dict) {
  259. OnError("'config' dictionary not found");
  260. return;
  261. }
  262. daemon_controller_->UpdateConfig(
  263. std::move(*config_dict),
  264. base::BindOnce(&Me2MeNativeMessagingHost::SendAsyncResult, weak_ptr_,
  265. std::move(response)));
  266. }
  267. void Me2MeNativeMessagingHost::ProcessGetDaemonConfig(
  268. base::Value::Dict message,
  269. base::Value::Dict response) {
  270. DCHECK(task_runner()->BelongsToCurrentThread());
  271. daemon_controller_->GetConfig(
  272. base::BindOnce(&Me2MeNativeMessagingHost::SendConfigResponse, weak_ptr_,
  273. std::move(response)));
  274. }
  275. void Me2MeNativeMessagingHost::ProcessGetPairedClients(
  276. base::Value::Dict message,
  277. base::Value::Dict response) {
  278. DCHECK(task_runner()->BelongsToCurrentThread());
  279. if (pairing_registry_.get()) {
  280. pairing_registry_->GetAllPairings(
  281. base::BindOnce(&Me2MeNativeMessagingHost::SendPairedClientsResponse,
  282. weak_ptr_, std::move(response)));
  283. } else {
  284. SendPairedClientsResponse(std::move(response),
  285. /*pairings=*/base::Value::List());
  286. }
  287. }
  288. void Me2MeNativeMessagingHost::ProcessGetUsageStatsConsent(
  289. base::Value::Dict message,
  290. base::Value::Dict response) {
  291. DCHECK(task_runner()->BelongsToCurrentThread());
  292. daemon_controller_->GetUsageStatsConsent(
  293. base::BindOnce(&Me2MeNativeMessagingHost::SendUsageStatsConsentResponse,
  294. weak_ptr_, std::move(response)));
  295. }
  296. void Me2MeNativeMessagingHost::ProcessStartDaemon(base::Value::Dict message,
  297. base::Value::Dict response) {
  298. DCHECK(task_runner()->BelongsToCurrentThread());
  299. if (needs_elevation_) {
  300. DelegationResult result = DelegateToElevatedHost(std::move(message));
  301. switch (result) {
  302. case DELEGATION_SUCCESS:
  303. return; // Result will be returned by elevated host.
  304. case DELEGATION_CANCELLED:
  305. SendAsyncResult(std::move(response),
  306. DaemonController::RESULT_CANCELLED);
  307. return;
  308. default:
  309. SendAsyncResult(std::move(response), DaemonController::RESULT_FAILED);
  310. return;
  311. }
  312. }
  313. absl::optional<bool> consent = message.FindBool("consent");
  314. if (!consent) {
  315. OnError("'consent' not found.");
  316. return;
  317. }
  318. absl::optional<base::Value::Dict> config_dict =
  319. ConfigDictionaryFromMessage(std::move(message));
  320. if (!config_dict) {
  321. OnError("'config' dictionary not found");
  322. return;
  323. }
  324. daemon_controller_->SetConfigAndStart(
  325. std::move(*config_dict), *consent,
  326. base::BindOnce(&Me2MeNativeMessagingHost::SendAsyncResult, weak_ptr_,
  327. std::move(response)));
  328. }
  329. void Me2MeNativeMessagingHost::ProcessStopDaemon(base::Value::Dict message,
  330. base::Value::Dict response) {
  331. DCHECK(task_runner()->BelongsToCurrentThread());
  332. if (needs_elevation_) {
  333. DelegationResult result = DelegateToElevatedHost(std::move(message));
  334. switch (result) {
  335. case DELEGATION_SUCCESS:
  336. return; // Result will be returned by elevated host.
  337. case DELEGATION_CANCELLED:
  338. SendAsyncResult(std::move(response),
  339. DaemonController::RESULT_CANCELLED);
  340. return;
  341. default:
  342. SendAsyncResult(std::move(response), DaemonController::RESULT_FAILED);
  343. return;
  344. }
  345. }
  346. daemon_controller_->Stop(
  347. base::BindOnce(&Me2MeNativeMessagingHost::SendAsyncResult, weak_ptr_,
  348. std::move(response)));
  349. }
  350. void Me2MeNativeMessagingHost::ProcessGetDaemonState(
  351. base::Value::Dict message,
  352. base::Value::Dict response) {
  353. DCHECK(task_runner()->BelongsToCurrentThread());
  354. DaemonController::State state = daemon_controller_->GetState();
  355. switch (state) {
  356. case DaemonController::STATE_NOT_IMPLEMENTED:
  357. response.Set("state", "NOT_IMPLEMENTED");
  358. break;
  359. case DaemonController::STATE_STOPPED:
  360. response.Set("state", "STOPPED");
  361. break;
  362. case DaemonController::STATE_STARTING:
  363. response.Set("state", "STARTING");
  364. break;
  365. case DaemonController::STATE_STARTED:
  366. response.Set("state", "STARTED");
  367. break;
  368. case DaemonController::STATE_STOPPING:
  369. response.Set("state", "STOPPING");
  370. break;
  371. case DaemonController::STATE_UNKNOWN:
  372. response.Set("state", "UNKNOWN");
  373. break;
  374. }
  375. SendMessageToClient(std::move(response));
  376. }
  377. void Me2MeNativeMessagingHost::ProcessGetHostClientId(
  378. base::Value::Dict message,
  379. base::Value::Dict response) {
  380. DCHECK(task_runner()->BelongsToCurrentThread());
  381. response.Set("clientId", google_apis::GetOAuth2ClientID(
  382. google_apis::CLIENT_REMOTING_HOST));
  383. SendMessageToClient(std::move(response));
  384. }
  385. void Me2MeNativeMessagingHost::ProcessGetCredentialsFromAuthCode(
  386. base::Value::Dict message,
  387. base::Value::Dict response,
  388. bool need_user_email) {
  389. DCHECK(task_runner()->BelongsToCurrentThread());
  390. std::string* auth_code = message.FindString("authorizationCode");
  391. if (!auth_code) {
  392. OnError("'authorizationCode' string not found.");
  393. return;
  394. }
  395. // Pass an empty redirect_uri value since it's not needed when exchanging
  396. // robot auth codes. See b/231442487 for more details.
  397. std::string redirect_uri;
  398. gaia::OAuthClientInfo oauth_client_info = {
  399. google_apis::GetOAuth2ClientID(google_apis::CLIENT_REMOTING_HOST),
  400. google_apis::GetOAuth2ClientSecret(google_apis::CLIENT_REMOTING_HOST),
  401. redirect_uri};
  402. oauth_client_->GetCredentialsFromAuthCode(
  403. oauth_client_info, std::move(*auth_code), need_user_email,
  404. base::BindOnce(&Me2MeNativeMessagingHost::SendCredentialsResponse,
  405. weak_ptr_, std::move(response)));
  406. }
  407. void Me2MeNativeMessagingHost::ProcessIt2mePermissionCheck(
  408. base::Value::Dict message,
  409. base::Value::Dict response) {
  410. DCHECK(task_runner()->BelongsToCurrentThread());
  411. daemon_controller_->CheckPermission(
  412. /* it2me */ true,
  413. base::BindOnce(&Me2MeNativeMessagingHost::SendBooleanResult, weak_ptr_,
  414. std::move(response)));
  415. }
  416. void Me2MeNativeMessagingHost::SendConfigResponse(
  417. base::Value::Dict response,
  418. absl::optional<base::Value::Dict> config) {
  419. DCHECK(task_runner()->BelongsToCurrentThread());
  420. if (config) {
  421. response.Set("config", std::move(*config));
  422. } else {
  423. response.Set("config", base::Value());
  424. }
  425. SendMessageToClient(std::move(response));
  426. }
  427. void Me2MeNativeMessagingHost::SendPairedClientsResponse(
  428. base::Value::Dict response,
  429. base::Value::List pairings) {
  430. DCHECK(task_runner()->BelongsToCurrentThread());
  431. response.Set("pairedClients", std::move(pairings));
  432. SendMessageToClient(std::move(response));
  433. }
  434. void Me2MeNativeMessagingHost::SendUsageStatsConsentResponse(
  435. base::Value::Dict response,
  436. const DaemonController::UsageStatsConsent& consent) {
  437. DCHECK(task_runner()->BelongsToCurrentThread());
  438. response.Set("supported", consent.supported);
  439. response.Set("allowed", consent.allowed);
  440. response.Set("setByPolicy", consent.set_by_policy);
  441. SendMessageToClient(std::move(response));
  442. }
  443. void Me2MeNativeMessagingHost::SendAsyncResult(
  444. base::Value::Dict response,
  445. DaemonController::AsyncResult result) {
  446. DCHECK(task_runner()->BelongsToCurrentThread());
  447. switch (result) {
  448. case DaemonController::RESULT_OK:
  449. response.Set("result", "OK");
  450. break;
  451. case DaemonController::RESULT_FAILED:
  452. response.Set("result", "FAILED");
  453. break;
  454. case DaemonController::RESULT_CANCELLED:
  455. response.Set("result", "CANCELLED");
  456. break;
  457. }
  458. SendMessageToClient(std::move(response));
  459. }
  460. void Me2MeNativeMessagingHost::SendBooleanResult(base::Value::Dict response,
  461. bool result) {
  462. DCHECK(task_runner()->BelongsToCurrentThread());
  463. response.Set("result", result);
  464. SendMessageToClient(std::move(response));
  465. }
  466. void Me2MeNativeMessagingHost::SendCredentialsResponse(
  467. base::Value::Dict response,
  468. const std::string& user_email,
  469. const std::string& refresh_token) {
  470. DCHECK(task_runner()->BelongsToCurrentThread());
  471. if (!user_email.empty()) {
  472. response.Set("userEmail", user_email);
  473. }
  474. response.Set("refreshToken", refresh_token);
  475. SendMessageToClient(std::move(response));
  476. }
  477. void Me2MeNativeMessagingHost::SendMessageToClient(
  478. base::Value::Dict message) const {
  479. DCHECK(task_runner()->BelongsToCurrentThread());
  480. std::string message_json;
  481. base::JSONWriter::Write(message, &message_json);
  482. client_->PostMessageFromNativeHost(message_json);
  483. }
  484. void Me2MeNativeMessagingHost::OnError(const std::string& error_message) {
  485. DCHECK(task_runner()->BelongsToCurrentThread());
  486. if (!error_message.empty()) {
  487. LOG(ERROR) << error_message;
  488. }
  489. // Trigger a host shutdown by sending an empty message.
  490. client_->CloseChannel(std::string());
  491. }
  492. #if BUILDFLAG(IS_WIN)
  493. Me2MeNativeMessagingHost::DelegationResult
  494. Me2MeNativeMessagingHost::DelegateToElevatedHost(base::Value::Dict message) {
  495. DCHECK(task_runner()->BelongsToCurrentThread());
  496. DCHECK(needs_elevation_);
  497. if (!elevated_host_) {
  498. elevated_host_ = std::make_unique<ElevatedNativeMessagingHost>(
  499. base::CommandLine::ForCurrentProcess()->GetProgram(),
  500. parent_window_handle_,
  501. /*elevate_process=*/true, base::Seconds(kElevatedHostTimeoutSeconds),
  502. client_);
  503. }
  504. ProcessLaunchResult result = elevated_host_->EnsureElevatedHostCreated();
  505. if (result == PROCESS_LAUNCH_RESULT_SUCCESS) {
  506. elevated_host_->SendMessage(
  507. base::Value::ToUniquePtrValue(base::Value(std::move(message))));
  508. }
  509. switch (result) {
  510. case PROCESS_LAUNCH_RESULT_SUCCESS:
  511. return DELEGATION_SUCCESS;
  512. case PROCESS_LAUNCH_RESULT_CANCELLED:
  513. return DELEGATION_CANCELLED;
  514. case PROCESS_LAUNCH_RESULT_FAILED:
  515. return DELEGATION_FAILED;
  516. }
  517. }
  518. #else // BUILDFLAG(IS_WIN)
  519. Me2MeNativeMessagingHost::DelegationResult
  520. Me2MeNativeMessagingHost::DelegateToElevatedHost(base::Value::Dict message) {
  521. NOTREACHED();
  522. return DELEGATION_FAILED;
  523. }
  524. #endif // !BUILDFLAG(IS_WIN)
  525. } // namespace remoting