Home | History | Annotate | Download | only in setup
      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 
      5 #include "remoting/host/setup/me2me_native_messaging_host.h"
      6 
      7 #include <string>
      8 
      9 #include "base/basictypes.h"
     10 #include "base/bind.h"
     11 #include "base/callback.h"
     12 #include "base/callback_helpers.h"
     13 #include "base/logging.h"
     14 #include "base/strings/stringize_macros.h"
     15 #include "base/threading/thread.h"
     16 #include "base/values.h"
     17 #include "google_apis/gaia/gaia_oauth_client.h"
     18 #include "google_apis/google_api_keys.h"
     19 #include "net/base/net_util.h"
     20 #include "remoting/base/rsa_key_pair.h"
     21 #include "remoting/host/pin_hash.h"
     22 #include "remoting/host/setup/oauth_client.h"
     23 #include "remoting/protocol/pairing_registry.h"
     24 
     25 namespace {
     26 
     27 // redirect_uri to use when authenticating service accounts (service account
     28 // codes are obtained "out-of-band", i.e., not through an OAuth redirect).
     29 const char* kServiceAccountRedirectUri = "oob";
     30 
     31 // Features supported in addition to the base protocol.
     32 const char* kSupportedFeatures[] = {
     33   "pairingRegistry",
     34   "oauthClient"
     35 };
     36 
     37 // Helper to extract the "config" part of a message as a DictionaryValue.
     38 // Returns NULL on failure, and logs an error message.
     39 scoped_ptr<base::DictionaryValue> ConfigDictionaryFromMessage(
     40     const base::DictionaryValue& message) {
     41   scoped_ptr<base::DictionaryValue> result;
     42   const base::DictionaryValue* config_dict;
     43   if (message.GetDictionary("config", &config_dict)) {
     44     result.reset(config_dict->DeepCopy());
     45   } else {
     46     LOG(ERROR) << "'config' dictionary not found";
     47   }
     48   return result.Pass();
     49 }
     50 
     51 }  // namespace
     52 
     53 namespace remoting {
     54 
     55 Me2MeNativeMessagingHost::Me2MeNativeMessagingHost(
     56     scoped_ptr<NativeMessagingChannel> channel,
     57     scoped_refptr<DaemonController> daemon_controller,
     58     scoped_refptr<protocol::PairingRegistry> pairing_registry,
     59     scoped_ptr<OAuthClient> oauth_client)
     60     : channel_(channel.Pass()),
     61       daemon_controller_(daemon_controller),
     62       pairing_registry_(pairing_registry),
     63       oauth_client_(oauth_client.Pass()),
     64       weak_factory_(this) {
     65   weak_ptr_ = weak_factory_.GetWeakPtr();
     66 }
     67 
     68 Me2MeNativeMessagingHost::~Me2MeNativeMessagingHost() {
     69   DCHECK(thread_checker_.CalledOnValidThread());
     70 }
     71 
     72 void Me2MeNativeMessagingHost::Start(
     73       const base::Closure& quit_closure) {
     74   DCHECK(thread_checker_.CalledOnValidThread());
     75 
     76   channel_->Start(
     77       base::Bind(&Me2MeNativeMessagingHost::ProcessMessage, weak_ptr_),
     78       quit_closure);
     79 }
     80 
     81 void Me2MeNativeMessagingHost::ProcessMessage(
     82     scoped_ptr<base::DictionaryValue> message) {
     83   DCHECK(thread_checker_.CalledOnValidThread());
     84 
     85   scoped_ptr<base::DictionaryValue> response(new base::DictionaryValue());
     86 
     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   const base::Value* id;
     90   if (message->Get("id", &id))
     91     response->Set("id", id->DeepCopy());
     92 
     93   std::string type;
     94   if (!message->GetString("type", &type)) {
     95     LOG(ERROR) << "'type' not found";
     96     channel_->SendMessage(scoped_ptr<base::DictionaryValue>());
     97     return;
     98   }
     99 
    100   response->SetString("type", type + "Response");
    101 
    102   bool success = false;
    103   if (type == "hello") {
    104     success = ProcessHello(*message, response.Pass());
    105   } else if (type == "clearPairedClients") {
    106     success = ProcessClearPairedClients(*message, response.Pass());
    107   } else if (type == "deletePairedClient") {
    108     success = ProcessDeletePairedClient(*message, response.Pass());
    109   } else if (type == "getHostName") {
    110     success = ProcessGetHostName(*message, response.Pass());
    111   } else if (type == "getPinHash") {
    112     success = ProcessGetPinHash(*message, response.Pass());
    113   } else if (type == "generateKeyPair") {
    114     success = ProcessGenerateKeyPair(*message, response.Pass());
    115   } else if (type == "updateDaemonConfig") {
    116     success = ProcessUpdateDaemonConfig(*message, response.Pass());
    117   } else if (type == "getDaemonConfig") {
    118     success = ProcessGetDaemonConfig(*message, response.Pass());
    119   } else if (type == "getPairedClients") {
    120     success = ProcessGetPairedClients(*message, response.Pass());
    121   } else if (type == "getUsageStatsConsent") {
    122     success = ProcessGetUsageStatsConsent(*message, response.Pass());
    123   } else if (type == "startDaemon") {
    124     success = ProcessStartDaemon(*message, response.Pass());
    125   } else if (type == "stopDaemon") {
    126     success = ProcessStopDaemon(*message, response.Pass());
    127   } else if (type == "getDaemonState") {
    128     success = ProcessGetDaemonState(*message, response.Pass());
    129   } else if (type == "getHostClientId") {
    130     success = ProcessGetHostClientId(*message, response.Pass());
    131   } else if (type == "getCredentialsFromAuthCode") {
    132     success = ProcessGetCredentialsFromAuthCode(*message, response.Pass());
    133   } else {
    134     LOG(ERROR) << "Unsupported request type: " << type;
    135   }
    136 
    137   if (!success)
    138     channel_->SendMessage(scoped_ptr<base::DictionaryValue>());
    139 }
    140 
    141 bool Me2MeNativeMessagingHost::ProcessHello(
    142     const base::DictionaryValue& message,
    143     scoped_ptr<base::DictionaryValue> response) {
    144   DCHECK(thread_checker_.CalledOnValidThread());
    145 
    146   response->SetString("version", STRINGIZE(VERSION));
    147   scoped_ptr<base::ListValue> supported_features_list(new base::ListValue());
    148   supported_features_list->AppendStrings(std::vector<std::string>(
    149       kSupportedFeatures, kSupportedFeatures + arraysize(kSupportedFeatures)));
    150   response->Set("supportedFeatures", supported_features_list.release());
    151   channel_->SendMessage(response.Pass());
    152   return true;
    153 }
    154 
    155 bool Me2MeNativeMessagingHost::ProcessClearPairedClients(
    156     const base::DictionaryValue& message,
    157     scoped_ptr<base::DictionaryValue> response) {
    158   DCHECK(thread_checker_.CalledOnValidThread());
    159 
    160   if (pairing_registry_) {
    161     pairing_registry_->ClearAllPairings(
    162         base::Bind(&Me2MeNativeMessagingHost::SendBooleanResult, weak_ptr_,
    163                    base::Passed(&response)));
    164   } else {
    165     SendBooleanResult(response.Pass(), false);
    166   }
    167   return true;
    168 }
    169 
    170 bool Me2MeNativeMessagingHost::ProcessDeletePairedClient(
    171     const base::DictionaryValue& message,
    172     scoped_ptr<base::DictionaryValue> response) {
    173   DCHECK(thread_checker_.CalledOnValidThread());
    174 
    175   std::string client_id;
    176   if (!message.GetString(protocol::PairingRegistry::kClientIdKey, &client_id)) {
    177     LOG(ERROR) << "'" << protocol::PairingRegistry::kClientIdKey
    178                << "' string not found.";
    179     return false;
    180   }
    181 
    182   if (pairing_registry_) {
    183     pairing_registry_->DeletePairing(
    184         client_id, base::Bind(&Me2MeNativeMessagingHost::SendBooleanResult,
    185                               weak_ptr_, base::Passed(&response)));
    186   } else {
    187     SendBooleanResult(response.Pass(), false);
    188   }
    189   return true;
    190 }
    191 
    192 bool Me2MeNativeMessagingHost::ProcessGetHostName(
    193     const base::DictionaryValue& message,
    194     scoped_ptr<base::DictionaryValue> response) {
    195   DCHECK(thread_checker_.CalledOnValidThread());
    196 
    197   response->SetString("hostname", net::GetHostName());
    198   channel_->SendMessage(response.Pass());
    199   return true;
    200 }
    201 
    202 bool Me2MeNativeMessagingHost::ProcessGetPinHash(
    203     const base::DictionaryValue& message,
    204     scoped_ptr<base::DictionaryValue> response) {
    205   DCHECK(thread_checker_.CalledOnValidThread());
    206 
    207   std::string host_id;
    208   if (!message.GetString("hostId", &host_id)) {
    209     LOG(ERROR) << "'hostId' not found: " << message;
    210     return false;
    211   }
    212   std::string pin;
    213   if (!message.GetString("pin", &pin)) {
    214     LOG(ERROR) << "'pin' not found: " << message;
    215     return false;
    216   }
    217   response->SetString("hash", MakeHostPinHash(host_id, pin));
    218   channel_->SendMessage(response.Pass());
    219   return true;
    220 }
    221 
    222 bool Me2MeNativeMessagingHost::ProcessGenerateKeyPair(
    223     const base::DictionaryValue& message,
    224     scoped_ptr<base::DictionaryValue> response) {
    225   DCHECK(thread_checker_.CalledOnValidThread());
    226 
    227   scoped_refptr<RsaKeyPair> key_pair = RsaKeyPair::Generate();
    228   response->SetString("privateKey", key_pair->ToString());
    229   response->SetString("publicKey", key_pair->GetPublicKey());
    230   channel_->SendMessage(response.Pass());
    231   return true;
    232 }
    233 
    234 bool Me2MeNativeMessagingHost::ProcessUpdateDaemonConfig(
    235     const base::DictionaryValue& message,
    236     scoped_ptr<base::DictionaryValue> response) {
    237   DCHECK(thread_checker_.CalledOnValidThread());
    238 
    239   scoped_ptr<base::DictionaryValue> config_dict =
    240       ConfigDictionaryFromMessage(message);
    241   if (!config_dict)
    242     return false;
    243 
    244   daemon_controller_->UpdateConfig(
    245       config_dict.Pass(),
    246       base::Bind(&Me2MeNativeMessagingHost::SendAsyncResult, weak_ptr_,
    247                  base::Passed(&response)));
    248   return true;
    249 }
    250 
    251 bool Me2MeNativeMessagingHost::ProcessGetDaemonConfig(
    252     const base::DictionaryValue& message,
    253     scoped_ptr<base::DictionaryValue> response) {
    254   DCHECK(thread_checker_.CalledOnValidThread());
    255 
    256   daemon_controller_->GetConfig(
    257       base::Bind(&Me2MeNativeMessagingHost::SendConfigResponse, weak_ptr_,
    258                  base::Passed(&response)));
    259   return true;
    260 }
    261 
    262 bool Me2MeNativeMessagingHost::ProcessGetPairedClients(
    263     const base::DictionaryValue& message,
    264     scoped_ptr<base::DictionaryValue> response) {
    265   DCHECK(thread_checker_.CalledOnValidThread());
    266 
    267   if (pairing_registry_) {
    268     pairing_registry_->GetAllPairings(
    269         base::Bind(&Me2MeNativeMessagingHost::SendPairedClientsResponse,
    270                    weak_ptr_, base::Passed(&response)));
    271   } else {
    272     scoped_ptr<base::ListValue> no_paired_clients(new base::ListValue);
    273     SendPairedClientsResponse(response.Pass(), no_paired_clients.Pass());
    274   }
    275   return true;
    276 }
    277 
    278 bool Me2MeNativeMessagingHost::ProcessGetUsageStatsConsent(
    279     const base::DictionaryValue& message,
    280     scoped_ptr<base::DictionaryValue> response) {
    281   DCHECK(thread_checker_.CalledOnValidThread());
    282 
    283   daemon_controller_->GetUsageStatsConsent(
    284       base::Bind(&Me2MeNativeMessagingHost::SendUsageStatsConsentResponse,
    285                  weak_ptr_, base::Passed(&response)));
    286   return true;
    287 }
    288 
    289 bool Me2MeNativeMessagingHost::ProcessStartDaemon(
    290     const base::DictionaryValue& message,
    291     scoped_ptr<base::DictionaryValue> response) {
    292   DCHECK(thread_checker_.CalledOnValidThread());
    293 
    294   bool consent;
    295   if (!message.GetBoolean("consent", &consent)) {
    296     LOG(ERROR) << "'consent' not found.";
    297     return false;
    298   }
    299 
    300   scoped_ptr<base::DictionaryValue> config_dict =
    301       ConfigDictionaryFromMessage(message);
    302   if (!config_dict)
    303     return false;
    304 
    305   daemon_controller_->SetConfigAndStart(
    306       config_dict.Pass(), consent,
    307       base::Bind(&Me2MeNativeMessagingHost::SendAsyncResult, weak_ptr_,
    308                  base::Passed(&response)));
    309   return true;
    310 }
    311 
    312 bool Me2MeNativeMessagingHost::ProcessStopDaemon(
    313     const base::DictionaryValue& message,
    314     scoped_ptr<base::DictionaryValue> response) {
    315   DCHECK(thread_checker_.CalledOnValidThread());
    316 
    317   daemon_controller_->Stop(
    318       base::Bind(&Me2MeNativeMessagingHost::SendAsyncResult, weak_ptr_,
    319                  base::Passed(&response)));
    320   return true;
    321 }
    322 
    323 bool Me2MeNativeMessagingHost::ProcessGetDaemonState(
    324     const base::DictionaryValue& message,
    325     scoped_ptr<base::DictionaryValue> response) {
    326   DCHECK(thread_checker_.CalledOnValidThread());
    327 
    328   DaemonController::State state = daemon_controller_->GetState();
    329   switch (state) {
    330     case DaemonController::STATE_NOT_IMPLEMENTED:
    331       response->SetString("state", "NOT_IMPLEMENTED");
    332       break;
    333     case DaemonController::STATE_NOT_INSTALLED:
    334       response->SetString("state", "NOT_INSTALLED");
    335       break;
    336     case DaemonController::STATE_INSTALLING:
    337       response->SetString("state", "INSTALLING");
    338       break;
    339     case DaemonController::STATE_STOPPED:
    340       response->SetString("state", "STOPPED");
    341       break;
    342     case DaemonController::STATE_STARTING:
    343       response->SetString("state", "STARTING");
    344       break;
    345     case DaemonController::STATE_STARTED:
    346       response->SetString("state", "STARTED");
    347       break;
    348     case DaemonController::STATE_STOPPING:
    349       response->SetString("state", "STOPPING");
    350       break;
    351     case DaemonController::STATE_UNKNOWN:
    352       response->SetString("state", "UNKNOWN");
    353       break;
    354   }
    355   channel_->SendMessage(response.Pass());
    356   return true;
    357 }
    358 
    359 bool Me2MeNativeMessagingHost::ProcessGetHostClientId(
    360     const base::DictionaryValue& message,
    361     scoped_ptr<base::DictionaryValue> response) {
    362   DCHECK(thread_checker_.CalledOnValidThread());
    363 
    364   response->SetString("clientId", google_apis::GetOAuth2ClientID(
    365       google_apis::CLIENT_REMOTING_HOST));
    366   channel_->SendMessage(response.Pass());
    367   return true;
    368 }
    369 
    370 bool Me2MeNativeMessagingHost::ProcessGetCredentialsFromAuthCode(
    371     const base::DictionaryValue& message,
    372     scoped_ptr<base::DictionaryValue> response) {
    373   DCHECK(thread_checker_.CalledOnValidThread());
    374 
    375   std::string auth_code;
    376   if (!message.GetString("authorizationCode", &auth_code)) {
    377     LOG(ERROR) << "'authorizationCode' string not found.";
    378     return false;
    379   }
    380 
    381   gaia::OAuthClientInfo oauth_client_info = {
    382     google_apis::GetOAuth2ClientID(google_apis::CLIENT_REMOTING_HOST),
    383     google_apis::GetOAuth2ClientSecret(google_apis::CLIENT_REMOTING_HOST),
    384     kServiceAccountRedirectUri
    385   };
    386 
    387   oauth_client_->GetCredentialsFromAuthCode(
    388       oauth_client_info, auth_code, base::Bind(
    389           &Me2MeNativeMessagingHost::SendCredentialsResponse, weak_ptr_,
    390           base::Passed(&response)));
    391 
    392   return true;
    393 }
    394 
    395 void Me2MeNativeMessagingHost::SendConfigResponse(
    396     scoped_ptr<base::DictionaryValue> response,
    397     scoped_ptr<base::DictionaryValue> config) {
    398   DCHECK(thread_checker_.CalledOnValidThread());
    399 
    400   if (config) {
    401     response->Set("config", config.release());
    402   } else {
    403     response->Set("config", Value::CreateNullValue());
    404   }
    405   channel_->SendMessage(response.Pass());
    406 }
    407 
    408 void Me2MeNativeMessagingHost::SendPairedClientsResponse(
    409     scoped_ptr<base::DictionaryValue> response,
    410     scoped_ptr<base::ListValue> pairings) {
    411   DCHECK(thread_checker_.CalledOnValidThread());
    412 
    413   response->Set("pairedClients", pairings.release());
    414   channel_->SendMessage(response.Pass());
    415 }
    416 
    417 void Me2MeNativeMessagingHost::SendUsageStatsConsentResponse(
    418     scoped_ptr<base::DictionaryValue> response,
    419     const DaemonController::UsageStatsConsent& consent) {
    420   DCHECK(thread_checker_.CalledOnValidThread());
    421 
    422   response->SetBoolean("supported", consent.supported);
    423   response->SetBoolean("allowed", consent.allowed);
    424   response->SetBoolean("setByPolicy", consent.set_by_policy);
    425   channel_->SendMessage(response.Pass());
    426 }
    427 
    428 void Me2MeNativeMessagingHost::SendAsyncResult(
    429     scoped_ptr<base::DictionaryValue> response,
    430     DaemonController::AsyncResult result) {
    431   DCHECK(thread_checker_.CalledOnValidThread());
    432 
    433   switch (result) {
    434     case DaemonController::RESULT_OK:
    435       response->SetString("result", "OK");
    436       break;
    437     case DaemonController::RESULT_FAILED:
    438       response->SetString("result", "FAILED");
    439       break;
    440     case DaemonController::RESULT_CANCELLED:
    441       response->SetString("result", "CANCELLED");
    442       break;
    443     case DaemonController::RESULT_FAILED_DIRECTORY:
    444       response->SetString("result", "FAILED_DIRECTORY");
    445       break;
    446   }
    447   channel_->SendMessage(response.Pass());
    448 }
    449 
    450 void Me2MeNativeMessagingHost::SendBooleanResult(
    451     scoped_ptr<base::DictionaryValue> response, bool result) {
    452   DCHECK(thread_checker_.CalledOnValidThread());
    453 
    454   response->SetBoolean("result", result);
    455   channel_->SendMessage(response.Pass());
    456 }
    457 
    458 void Me2MeNativeMessagingHost::SendCredentialsResponse(
    459     scoped_ptr<base::DictionaryValue> response,
    460     const std::string& user_email,
    461     const std::string& refresh_token) {
    462   DCHECK(thread_checker_.CalledOnValidThread());
    463 
    464   response->SetString("userEmail", user_email);
    465   response->SetString("refreshToken", refresh_token);
    466   channel_->SendMessage(response.Pass());
    467 }
    468 
    469 }  // namespace remoting
    470