Home | History | Annotate | Download | only in src
      1 // Copyright 2015 The Weave 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 #ifndef LIBWEAVE_SRC_DEVICE_REGISTRATION_INFO_H_
      6 #define LIBWEAVE_SRC_DEVICE_REGISTRATION_INFO_H_
      7 
      8 #include <map>
      9 #include <memory>
     10 #include <string>
     11 #include <utility>
     12 #include <vector>
     13 
     14 #include <base/callback.h>
     15 #include <base/macros.h>
     16 #include <base/memory/weak_ptr.h>
     17 #include <base/time/time.h>
     18 #include <weave/device.h>
     19 #include <weave/error.h>
     20 #include <weave/provider/http_client.h>
     21 
     22 #include "src/backoff_entry.h"
     23 #include "src/commands/cloud_command_update_interface.h"
     24 #include "src/component_manager.h"
     25 #include "src/config.h"
     26 #include "src/data_encoding.h"
     27 #include "src/notification/notification_channel.h"
     28 #include "src/notification/notification_delegate.h"
     29 #include "src/notification/pull_channel.h"
     30 
     31 namespace base {
     32 class DictionaryValue;
     33 }  // namespace base
     34 
     35 namespace weave {
     36 
     37 class StateManager;
     38 
     39 namespace provider {
     40 class Network;
     41 class TaskRunner;
     42 }
     43 
     44 namespace privet {
     45 class AuthManager;
     46 }
     47 
     48 // The DeviceRegistrationInfo class represents device registration information.
     49 class DeviceRegistrationInfo : public NotificationDelegate,
     50                                public CloudCommandUpdateInterface {
     51  public:
     52   using CloudRequestDoneCallback =
     53       base::Callback<void(const base::DictionaryValue& response,
     54                           ErrorPtr error)>;
     55 
     56   DeviceRegistrationInfo(Config* config,
     57                          ComponentManager* component_manager,
     58                          provider::TaskRunner* task_runner,
     59                          provider::HttpClient* http_client,
     60                          provider::Network* network,
     61                          privet::AuthManager* auth_manager);
     62 
     63   ~DeviceRegistrationInfo() override;
     64 
     65   void AddGcdStateChangedCallback(
     66       const Device::GcdStateChangedCallback& callback);
     67   void RegisterDevice(const std::string& ticket_id,
     68                       const DoneCallback& callback);
     69 
     70   void UpdateDeviceInfo(const std::string& name,
     71                         const std::string& description,
     72                         const std::string& location);
     73   void UpdateBaseConfig(AuthScope anonymous_access_role,
     74                         bool local_discovery_enabled,
     75                         bool local_pairing_enabled);
     76   bool UpdateServiceConfig(const std::string& client_id,
     77                            const std::string& client_secret,
     78                            const std::string& api_key,
     79                            const std::string& oauth_url,
     80                            const std::string& service_url,
     81                            const std::string& xmpp_endpoint,
     82                            ErrorPtr* error);
     83 
     84   void GetDeviceInfo(const CloudRequestDoneCallback& callback);
     85 
     86   // Returns the GCD service request URL. If |subpath| is specified, it is
     87   // appended to the base URL which is normally
     88   //    https://www.googleapis.com/weave/v1/".
     89   // If |params| are specified, each key-value pair is formatted using
     90   // WebParamsEncode() and appended to URL as a query
     91   // string.
     92   // So, calling:
     93   //    GetServiceURL("ticket", {{"key","apiKey"}})
     94   // will return something like:
     95   //    https://www.googleapis.com/weave/v1/ticket?key=apiKey
     96   std::string GetServiceURL(const std::string& subpath = {},
     97                             const WebParamList& params = {}) const;
     98 
     99   // Returns a service URL to access the registered device on GCD server.
    100   // The base URL used to construct the full URL looks like this:
    101   //    https://www.googleapis.com/weave/v1/devices/<cloud_id>/
    102   std::string GetDeviceURL(const std::string& subpath = {},
    103                            const WebParamList& params = {}) const;
    104 
    105   // Similar to GetServiceURL, GetOAuthURL() returns a URL of OAuth 2.0 server.
    106   // The base URL used is https://accounts.google.com/o/oauth2/.
    107   std::string GetOAuthURL(const std::string& subpath = {},
    108                           const WebParamList& params = {}) const;
    109 
    110   // Starts GCD device if credentials available.
    111   void Start();
    112 
    113   // Updates a command (override from CloudCommandUpdateInterface).
    114   void UpdateCommand(const std::string& command_id,
    115                      const base::DictionaryValue& command_patch,
    116                      const DoneCallback& callback) override;
    117 
    118   // TODO(vitalybuka): remove getters and pass config to dependent code.
    119   const Config::Settings& GetSettings() const { return config_->GetSettings(); }
    120   Config* GetMutableConfig() { return config_; }
    121 
    122   GcdState GetGcdState() const { return gcd_state_; }
    123 
    124  private:
    125   friend class DeviceRegistrationInfoTest;
    126 
    127   base::WeakPtr<DeviceRegistrationInfo> AsWeakPtr() {
    128     return weak_factory_.GetWeakPtr();
    129   }
    130 
    131   // Checks whether we have credentials generated during registration.
    132   bool HaveRegistrationCredentials() const;
    133   // Calls HaveRegistrationCredentials() and logs an error if no credentials
    134   // are available.
    135   bool VerifyRegistrationCredentials(ErrorPtr* error) const;
    136 
    137   // Cause DeviceRegistrationInfo to attempt to connect to cloud server on
    138   // its own later.
    139   void ScheduleCloudConnection(const base::TimeDelta& delay);
    140 
    141   // Initiates the connection to the cloud server.
    142   // Device will do required start up chores and then start to listen
    143   // to new commands.
    144   void ConnectToCloud(ErrorPtr error);
    145   // Notification called when ConnectToCloud() succeeds.
    146   void OnConnectedToCloud(ErrorPtr error);
    147 
    148   // Forcibly refreshes the access token.
    149   void RefreshAccessToken(const DoneCallback& callback);
    150 
    151   // Callbacks for RefreshAccessToken().
    152   void OnRefreshAccessTokenDone(
    153       const DoneCallback& callback,
    154       std::unique_ptr<provider::HttpClient::Response> response,
    155       ErrorPtr error);
    156 
    157   // Parse the OAuth response, and sets registration status to
    158   // kInvalidCredentials if our registration is no longer valid.
    159   std::unique_ptr<base::DictionaryValue> ParseOAuthResponse(
    160       const provider::HttpClient::Response& response,
    161       ErrorPtr* error);
    162 
    163   // This attempts to open a notification channel. The channel needs to be
    164   // restarted anytime the access_token is refreshed.
    165   void StartNotificationChannel();
    166 
    167   // Do a HTTPS request to cloud services.
    168   // Handles many cases like reauthorization, 5xx HTTP response codes
    169   // and device removal.  It is a recommended way to do cloud API
    170   // requests.
    171   // TODO(antonm): Consider moving into some other class.
    172   void DoCloudRequest(provider::HttpClient::Method method,
    173                       const std::string& url,
    174                       const base::DictionaryValue* body,
    175                       const CloudRequestDoneCallback& callback);
    176 
    177   // Helper for DoCloudRequest().
    178   struct CloudRequestData {
    179     provider::HttpClient::Method method;
    180     std::string url;
    181     std::string body;
    182     CloudRequestDoneCallback callback;
    183   };
    184   void SendCloudRequest(const std::shared_ptr<const CloudRequestData>& data);
    185   void OnCloudRequestDone(
    186       const std::shared_ptr<const CloudRequestData>& data,
    187       std::unique_ptr<provider::HttpClient::Response> response,
    188       ErrorPtr error);
    189   void RetryCloudRequest(const std::shared_ptr<const CloudRequestData>& data);
    190   void OnAccessTokenRefreshed(
    191       const std::shared_ptr<const CloudRequestData>& data,
    192       ErrorPtr error);
    193   void CheckAccessTokenError(ErrorPtr error);
    194 
    195   void UpdateDeviceResource(const DoneCallback& callback);
    196   void StartQueuedUpdateDeviceResource();
    197   void OnUpdateDeviceResourceDone(const base::DictionaryValue& device_info,
    198                                   ErrorPtr error);
    199   void OnUpdateDeviceResourceError(ErrorPtr error);
    200 
    201   void SendAuthInfo();
    202   void OnSendAuthInfoDone(const std::vector<uint8_t>& token,
    203                           const base::DictionaryValue& body,
    204                           ErrorPtr error);
    205 
    206   // Callback from GetDeviceInfo() to retrieve the device resource timestamp
    207   // and retry UpdateDeviceResource() call.
    208   void OnDeviceInfoRetrieved(const base::DictionaryValue& device_info,
    209                              ErrorPtr error);
    210 
    211   // Extracts the timestamp from the device resource and sets it to
    212   // |last_device_resource_updated_timestamp_|.
    213   // Returns false if the "lastUpdateTimeMs" field is not found in the device
    214   // resource or it is invalid.
    215   bool UpdateDeviceInfoTimestamp(const base::DictionaryValue& device_info);
    216 
    217   void FetchCommands(
    218       const base::Callback<void(const base::ListValue&, ErrorPtr)>& callback,
    219       const std::string& reason);
    220   void OnFetchCommandsDone(
    221       const base::Callback<void(const base::ListValue&, ErrorPtr)>& callback,
    222       const base::DictionaryValue& json,
    223       ErrorPtr);
    224   // Called when FetchCommands completes (with either success or error).
    225   // This method reschedules any pending/queued fetch requests.
    226   void OnFetchCommandsReturned();
    227 
    228   // Processes the command list that is fetched from the server on connection.
    229   // Aborts commands which are in transitional states and publishes queued
    230   // commands which are queued.
    231   void ProcessInitialCommandList(const base::ListValue& commands,
    232                                  ErrorPtr error);
    233 
    234   void PublishCommands(const base::ListValue& commands, ErrorPtr error);
    235   void PublishCommand(const base::DictionaryValue& command);
    236 
    237   // Helper function to pull the pending command list from the server using
    238   // FetchCommands() and make them available on D-Bus with PublishCommands().
    239   // |backup_fetch| is set to true when performing backup ("just-in-case")
    240   // command fetch while XMPP channel is up and running.
    241   void FetchAndPublishCommands(const std::string& reason);
    242 
    243   void PublishStateUpdates();
    244   void OnPublishStateDone(ComponentManager::UpdateID update_id,
    245                           const base::DictionaryValue& reply,
    246                           ErrorPtr error);
    247   void OnPublishStateError(ErrorPtr error);
    248 
    249   // If unrecoverable error occurred (e.g. error parsing command instance),
    250   // notify the server that the command is aborted by the device.
    251   void NotifyCommandAborted(const std::string& command_id, ErrorPtr error);
    252 
    253   // Builds Cloud API devices collection REST resource which matches
    254   // current state of the device including command definitions
    255   // for all supported commands and current device state.
    256   std::unique_ptr<base::DictionaryValue> BuildDeviceResource() const;
    257 
    258   void SetGcdState(GcdState new_state);
    259   void SetDeviceId(const std::string& cloud_id);
    260 
    261   // Callback called when command definitions are changed to re-publish new CDD.
    262   void OnTraitDefsChanged();
    263   void OnComponentTreeChanged();
    264   void OnStateChanged();
    265 
    266   // Overrides from NotificationDelegate.
    267   void OnConnected(const std::string& channel_name) override;
    268   void OnDisconnected() override;
    269   void OnPermanentFailure() override;
    270   void OnCommandCreated(const base::DictionaryValue& command,
    271                         const std::string& channel_name) override;
    272   void OnDeviceDeleted(const std::string& cloud_id) override;
    273 
    274   // Wipes out the device registration information and stops server connections.
    275   void RemoveCredentials();
    276 
    277   void RegisterDeviceError(const DoneCallback& callback, ErrorPtr error);
    278   void RegisterDeviceOnTicketSent(
    279       const std::string& ticket_id,
    280       const DoneCallback& callback,
    281       std::unique_ptr<provider::HttpClient::Response> response,
    282       ErrorPtr error);
    283   void RegisterDeviceOnTicketFinalized(
    284       const DoneCallback& callback,
    285       std::unique_ptr<provider::HttpClient::Response> response,
    286       ErrorPtr error);
    287   void RegisterDeviceOnAuthCodeSent(
    288       const std::string& cloud_id,
    289       const std::string& robot_account,
    290       const DoneCallback& callback,
    291       std::unique_ptr<provider::HttpClient::Response> response,
    292       ErrorPtr error);
    293 
    294   // Transient data
    295   std::string access_token_;
    296   base::Time access_token_expiration_;
    297   // The time stamp of last device resource update on the server.
    298   std::string last_device_resource_updated_timestamp_;
    299   // Set to true if the device has connected to the cloud server correctly.
    300   // At this point, normal state and command updates can be dispatched to the
    301   // server.
    302   bool connected_to_cloud_{false};
    303 
    304   // HTTP transport used for communications.
    305   provider::HttpClient* http_client_{nullptr};
    306 
    307   provider::TaskRunner* task_runner_{nullptr};
    308 
    309   Config* config_{nullptr};
    310 
    311   // Global component manager.
    312   ComponentManager* component_manager_{nullptr};
    313 
    314   // Backoff manager for DoCloudRequest() method.
    315   std::unique_ptr<BackoffEntry::Policy> cloud_backoff_policy_;
    316   std::unique_ptr<BackoffEntry> cloud_backoff_entry_;
    317   std::unique_ptr<BackoffEntry> oauth2_backoff_entry_;
    318 
    319   // Flag set to true while a device state update patch request is in flight
    320   // to the cloud server.
    321   bool device_state_update_pending_{false};
    322 
    323   // Set to true when command queue fetch request is in flight to the server.
    324   bool fetch_commands_request_sent_{false};
    325   // Set to true when another command queue fetch request is queued while
    326   // another one was in flight.
    327   bool fetch_commands_request_queued_{false};
    328   // Specifies the reason for queued command fetch request.
    329   std::string queued_fetch_reason_;
    330 
    331   using ResourceUpdateCallbackList = std::vector<DoneCallback>;
    332   // Callbacks for device resource update request currently in flight to the
    333   // cloud server.
    334   ResourceUpdateCallbackList in_progress_resource_update_callbacks_;
    335   // Callbacks for device resource update requests queued while another request
    336   // is in flight to the cloud server.
    337   ResourceUpdateCallbackList queued_resource_update_callbacks_;
    338 
    339   bool auth_info_update_inprogress_{false};
    340 
    341   std::unique_ptr<NotificationChannel> primary_notification_channel_;
    342   std::unique_ptr<PullChannel> pull_channel_;
    343   NotificationChannel* current_notification_channel_{nullptr};
    344   bool notification_channel_starting_{false};
    345 
    346   provider::Network* network_{nullptr};
    347   privet::AuthManager* auth_manager_{nullptr};
    348 
    349   // Tracks our GCD state.
    350   GcdState gcd_state_{GcdState::kUnconfigured};
    351 
    352   std::vector<Device::GcdStateChangedCallback> gcd_state_changed_callbacks_;
    353 
    354   base::WeakPtrFactory<DeviceRegistrationInfo> weak_factory_{this};
    355   DISALLOW_COPY_AND_ASSIGN(DeviceRegistrationInfo);
    356 };
    357 
    358 }  // namespace weave
    359 
    360 #endif  // LIBWEAVE_SRC_DEVICE_REGISTRATION_INFO_H_
    361