1 // Copyright (c) 2012 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 5 #include "remoting/host/setup/host_starter.h" 6 7 #include "base/guid.h" 8 #include "base/thread_task_runner_handle.h" 9 #include "base/values.h" 10 #include "google_apis/google_api_keys.h" 11 #include "remoting/host/pin_hash.h" 12 #include "remoting/host/setup/oauth_helper.h" 13 14 namespace { 15 const int kMaxGetTokensRetries = 3; 16 } // namespace 17 18 namespace remoting { 19 20 HostStarter::HostStarter( 21 scoped_ptr<gaia::GaiaOAuthClient> oauth_client, 22 scoped_ptr<remoting::ServiceClient> service_client, 23 scoped_ptr<remoting::DaemonController> daemon_controller) 24 : oauth_client_(oauth_client.Pass()), 25 service_client_(service_client.Pass()), 26 daemon_controller_(daemon_controller.Pass()), 27 consent_to_data_collection_(false), 28 weak_ptr_factory_(this), 29 weak_ptr_(weak_ptr_factory_.GetWeakPtr()) { 30 main_task_runner_ = base::ThreadTaskRunnerHandle::Get(); 31 } 32 33 HostStarter::~HostStarter() { 34 } 35 36 scoped_ptr<HostStarter> HostStarter::Create( 37 const std::string& chromoting_hosts_url, 38 net::URLRequestContextGetter* url_request_context_getter) { 39 scoped_ptr<gaia::GaiaOAuthClient> oauth_client( 40 new gaia::GaiaOAuthClient(url_request_context_getter)); 41 scoped_ptr<remoting::ServiceClient> service_client( 42 new remoting::ServiceClient( 43 chromoting_hosts_url, url_request_context_getter)); 44 scoped_ptr<remoting::DaemonController> daemon_controller( 45 remoting::DaemonController::Create()); 46 return scoped_ptr<HostStarter>( 47 new HostStarter(oauth_client.Pass(), service_client.Pass(), 48 daemon_controller.Pass())); 49 } 50 51 void HostStarter::StartHost( 52 const std::string& host_name, 53 const std::string& host_pin, 54 bool consent_to_data_collection, 55 const std::string& auth_code, 56 const std::string& redirect_url, 57 CompletionCallback on_done) { 58 DCHECK(main_task_runner_->BelongsToCurrentThread()); 59 DCHECK(on_done_.is_null()); 60 61 host_name_ = host_name; 62 host_pin_ = host_pin; 63 consent_to_data_collection_ = consent_to_data_collection; 64 on_done_ = on_done; 65 oauth_client_info_.client_id = 66 google_apis::GetOAuth2ClientID(google_apis::CLIENT_REMOTING); 67 oauth_client_info_.client_secret = 68 google_apis::GetOAuth2ClientSecret(google_apis::CLIENT_REMOTING); 69 oauth_client_info_.redirect_uri = redirect_url; 70 // Map the authorization code to refresh and access tokens. 71 oauth_client_->GetTokensFromAuthCode(oauth_client_info_, auth_code, 72 kMaxGetTokensRetries, this); 73 } 74 75 void HostStarter::OnGetTokensResponse( 76 const std::string& refresh_token, 77 const std::string& access_token, 78 int expires_in_seconds) { 79 if (!main_task_runner_->BelongsToCurrentThread()) { 80 main_task_runner_->PostTask(FROM_HERE, base::Bind( 81 &HostStarter::OnGetTokensResponse, weak_ptr_, 82 refresh_token, access_token, expires_in_seconds)); 83 return; 84 } 85 refresh_token_ = refresh_token; 86 access_token_ = access_token; 87 // Get the email corresponding to the access token. 88 oauth_client_->GetUserEmail(access_token_, 1, this); 89 } 90 91 void HostStarter::OnRefreshTokenResponse( 92 const std::string& access_token, 93 int expires_in_seconds) { 94 // We never request a refresh token, so this call is not expected. 95 NOTREACHED(); 96 } 97 98 void HostStarter::OnGetUserEmailResponse(const std::string& user_email) { 99 if (!main_task_runner_->BelongsToCurrentThread()) { 100 main_task_runner_->PostTask(FROM_HERE, base::Bind( 101 &HostStarter::OnGetUserEmailResponse, weak_ptr_, user_email)); 102 return; 103 } 104 user_email_ = user_email; 105 // Register the host. 106 host_id_ = base::GenerateGUID(); 107 key_pair_ = RsaKeyPair::Generate(); 108 service_client_->RegisterHost( 109 host_id_, host_name_, key_pair_->GetPublicKey(), access_token_, this); 110 } 111 112 void HostStarter::OnHostRegistered() { 113 if (!main_task_runner_->BelongsToCurrentThread()) { 114 main_task_runner_->PostTask(FROM_HERE, base::Bind( 115 &HostStarter::OnHostRegistered, weak_ptr_)); 116 return; 117 } 118 // Start the host. 119 std::string host_secret_hash = remoting::MakeHostPinHash(host_id_, host_pin_); 120 scoped_ptr<base::DictionaryValue> config(new base::DictionaryValue()); 121 config->SetString("xmpp_login", user_email_); 122 config->SetString("oauth_refresh_token", refresh_token_); 123 config->SetString("host_id", host_id_); 124 config->SetString("host_name", host_name_); 125 config->SetString("private_key", key_pair_->ToString()); 126 config->SetString("host_secret_hash", host_secret_hash); 127 daemon_controller_->SetConfigAndStart( 128 config.Pass(), consent_to_data_collection_, 129 base::Bind(&HostStarter::OnHostStarted, base::Unretained(this))); 130 } 131 132 void HostStarter::OnHostStarted(DaemonController::AsyncResult result) { 133 if (!main_task_runner_->BelongsToCurrentThread()) { 134 main_task_runner_->PostTask(FROM_HERE, base::Bind( 135 &HostStarter::OnHostStarted, weak_ptr_, result)); 136 return; 137 } 138 if (result != DaemonController::RESULT_OK) { 139 service_client_->UnregisterHost(host_id_, access_token_, this); 140 return; 141 } 142 Result done_result = (result == DaemonController::RESULT_OK) ? 143 START_COMPLETE : START_ERROR; 144 CompletionCallback cb = on_done_; 145 on_done_.Reset(); 146 cb.Run(done_result); 147 } 148 149 void HostStarter::OnOAuthError() { 150 if (!main_task_runner_->BelongsToCurrentThread()) { 151 main_task_runner_->PostTask(FROM_HERE, base::Bind( 152 &HostStarter::OnOAuthError, weak_ptr_)); 153 return; 154 } 155 CompletionCallback cb = on_done_; 156 on_done_.Reset(); 157 cb.Run(OAUTH_ERROR); 158 } 159 160 void HostStarter::OnNetworkError(int response_code) { 161 if (!main_task_runner_->BelongsToCurrentThread()) { 162 main_task_runner_->PostTask(FROM_HERE, base::Bind( 163 &HostStarter::OnNetworkError, weak_ptr_, response_code)); 164 return; 165 } 166 CompletionCallback cb = on_done_; 167 on_done_.Reset(); 168 cb.Run(NETWORK_ERROR); 169 } 170 171 void HostStarter::OnHostUnregistered() { 172 if (!main_task_runner_->BelongsToCurrentThread()) { 173 main_task_runner_->PostTask(FROM_HERE, base::Bind( 174 &HostStarter::OnHostUnregistered, weak_ptr_)); 175 return; 176 } 177 CompletionCallback cb = on_done_; 178 on_done_.Reset(); 179 cb.Run(START_ERROR); 180 } 181 182 } // namespace remoting 183