blob: f985d42ce45ab529523482bfc814fa5a2c811fc4 [file] [log] [blame]
Alex Vakulenko3cb466c2014-04-15 11:36:32 -07001// Copyright 2014 The Chromium OS 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
Alex Vakulenkob3aac252014-05-07 17:35:24 -07005#ifndef BUFFET_DEVICE_REGISTRATION_INFO_H_
6#define BUFFET_DEVICE_REGISTRATION_INFO_H_
Alex Vakulenko3cb466c2014-04-15 11:36:32 -07007
Alex Vakulenko3cb466c2014-04-15 11:36:32 -07008#include <map>
9#include <memory>
Alex Vakulenko5841c302014-07-23 10:49:49 -070010#include <string>
Alex Vakulenkob3aac252014-05-07 17:35:24 -070011#include <utility>
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070012
Anton Muhinac661ab2014-10-03 20:29:48 +040013#include <base/callback.h>
Alex Vakulenko132617a2014-09-04 08:59:43 -070014#include <base/macros.h>
Christopher Wileycd419662015-02-06 17:51:43 -080015#include <base/memory/weak_ptr.h>
Nathan Bullockd9e0bcd2015-02-11 11:36:39 -050016#include <base/message_loop/message_loop.h>
Alex Vakulenkoa3062c52014-04-21 17:05:51 -070017#include <base/time/time.h>
Alex Vakulenkoe4879a22014-08-20 15:47:36 -070018#include <chromeos/data_encoding.h>
Alex Vakulenkoa8b95bc2014-08-27 11:00:57 -070019#include <chromeos/errors/error.h>
20#include <chromeos/http/http_transport.h>
Alex Vakulenkoa3062c52014-04-21 17:05:51 -070021
Christopher Wileyc900e482015-02-15 15:42:04 -080022#include "buffet/registration_status.h"
Christopher Wiley006e94e2014-05-02 13:44:48 -070023#include "buffet/storage_interface.h"
Nathan Bullockd9e0bcd2015-02-11 11:36:39 -050024#include "buffet/xmpp/xmpp_client.h"
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070025
26namespace base {
Vitaly Buka6ca3ad62015-03-11 17:03:23 -070027class DictionaryValue;
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070028} // namespace base
29
Anton Muhin332df192014-11-22 05:59:14 +040030namespace chromeos {
31class KeyValueStore;
32} // namespace chromeos
33
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070034namespace buffet {
35
Alex Vakulenko1f30a622014-07-23 11:13:15 -070036class CommandManager;
Alex Vakulenko07216fe2014-09-19 15:31:09 -070037class StateManager;
Alex Vakulenko1f30a622014-07-23 11:13:15 -070038
Alex Vakulenkob3aac252014-05-07 17:35:24 -070039extern const char kErrorDomainOAuth2[];
40extern const char kErrorDomainGCD[];
41extern const char kErrorDomainGCDServer[];
Alex Vakulenkob3aac252014-05-07 17:35:24 -070042
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070043// The DeviceRegistrationInfo class represents device registration information.
Nathan Bullockd9e0bcd2015-02-11 11:36:39 -050044class DeviceRegistrationInfo : public base::MessageLoopForIO::Watcher {
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070045 public:
Alex Vakulenko8e34d392014-04-29 11:02:56 -070046 // This is a helper class for unit testing.
47 class TestHelper;
Christopher Wileye0fdeee2015-02-07 18:29:32 -080048
Alex Vakulenkocca20932014-08-20 17:35:12 -070049 DeviceRegistrationInfo(
50 const std::shared_ptr<CommandManager>& command_manager,
Anton Muhinb8315622014-11-20 03:17:05 +040051 const std::shared_ptr<StateManager>& state_manager,
Anton Muhin332df192014-11-22 05:59:14 +040052 std::unique_ptr<chromeos::KeyValueStore> config_store,
Alex Vakulenkocca20932014-08-20 17:35:12 -070053 const std::shared_ptr<chromeos::http::Transport>& transport,
Christopher Wileyc900e482015-02-15 15:42:04 -080054 const std::shared_ptr<StorageInterface>& state_store,
Vitaly Buka7ad8ffb2015-03-20 09:46:57 -070055 const base::Closure& on_status_changed);
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070056
Nathan Bullockd9e0bcd2015-02-11 11:36:39 -050057 ~DeviceRegistrationInfo() override;
58
Nathan Bullockf12f7f02015-02-20 14:46:53 -050059 void OnFileCanReadWithoutBlocking(int fd) override;
Nathan Bullockd9e0bcd2015-02-11 11:36:39 -050060
61 void OnFileCanWriteWithoutBlocking(int fd) override {
62 LOG(FATAL) << "No write watcher is configured";
63 }
Anton Muhin332df192014-11-22 05:59:14 +040064
Christopher Wileyc900e482015-02-15 15:42:04 -080065 // Returns our current best known registration status.
66 RegistrationStatus GetRegistrationStatus() const {
67 return registration_status_;
68 }
69
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070070 // Returns the authorization HTTP header that can be used to talk
71 // to GCD server for authenticated device communication.
Alex Vakulenko8e34d392014-04-29 11:02:56 -070072 // Make sure ValidateAndRefreshAccessToken() is called before this call.
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070073 std::pair<std::string, std::string> GetAuthorizationHeader() const;
74
75 // Returns the GCD service request URL. If |subpath| is specified, it is
76 // appended to the base URL which is normally
77 // https://www.googleapis.com/clouddevices/v1/".
78 // If |params| are specified, each key-value pair is formatted using
Alex Vakulenkoe4879a22014-08-20 15:47:36 -070079 // chromeos::data_encoding::WebParamsEncode() and appended to URL as a query
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070080 // string.
81 // So, calling:
82 // GetServiceURL("ticket", {{"key","apiKey"}})
83 // will return something like:
84 // https://www.googleapis.com/clouddevices/v1/ticket?key=apiKey
85 std::string GetServiceURL(
86 const std::string& subpath = {},
Alex Vakulenkoe4879a22014-08-20 15:47:36 -070087 const chromeos::data_encoding::WebParamList& params = {}) const;
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070088
89 // Returns a service URL to access the registered device on GCD server.
90 // The base URL used to construct the full URL looks like this:
91 // https://www.googleapis.com/clouddevices/v1/devices/<device_id>/
92 std::string GetDeviceURL(
93 const std::string& subpath = {},
Alex Vakulenkoe4879a22014-08-20 15:47:36 -070094 const chromeos::data_encoding::WebParamList& params = {}) const;
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070095
96 // Similar to GetServiceURL, GetOAuthURL() returns a URL of OAuth 2.0 server.
97 // The base URL used is https://accounts.google.com/o/oauth2/.
98 std::string GetOAuthURL(
99 const std::string& subpath = {},
Alex Vakulenkoe4879a22014-08-20 15:47:36 -0700100 const chromeos::data_encoding::WebParamList& params = {}) const;
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700101
Vitaly Buka620bd7e2015-03-16 01:07:01 -0700102 // Returns the registered device ID (GUID) or empty string.
103 const std::string& GetDeviceId() const;
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700104
105 // Loads the device registration information from cache.
106 bool Load();
107
108 // Checks for the valid device registration as well as refreshes
109 // the device access token, if available.
Alex Vakulenko5f472062014-08-14 17:54:04 -0700110 bool CheckRegistration(chromeos::ErrorPtr* error);
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700111
112 // Gets the full device description JSON object, or nullptr if
113 // the device is not registered or communication failure.
Vitaly Buka6ca3ad62015-03-11 17:03:23 -0700114 std::unique_ptr<base::DictionaryValue> GetDeviceInfo(
115 chromeos::ErrorPtr* error);
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700116
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400117 // Registers the device.
118 //
119 // |params| are a list of key-value pairs of device information,
120 // such as client_id, client_secret, and so on. If a particular key-value pair
121 // is omitted, a default value is used when possible.
122 // Returns a device ID on success.
Alex Vakulenkoa9044342014-08-23 19:31:27 -0700123 // The values are all strings for now.
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400124 std::string RegisterDevice(
Alex Vakulenkoa9044342014-08-23 19:31:27 -0700125 const std::map<std::string, std::string>& params,
Alex Vakulenko5f472062014-08-14 17:54:04 -0700126 chromeos::ErrorPtr* error);
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700127
Anton Muhin59755522014-11-05 21:30:12 +0400128 // Updates a command.
129 // TODO(antonm): Should solve the issues with async vs. sync.
130 // TODO(antonm): Consider moving some other class.
131 void UpdateCommand(const std::string& command_id,
132 const base::DictionaryValue& command_patch);
133
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700134 private:
Christopher Wileyba983c82015-03-05 16:32:23 -0800135 // Cause DeviceRegistrationInfo to attempt to StartDevice on its own later.
136 void ScheduleStartDevice(const base::TimeDelta& later);
137
138 // Starts device execution.
139 // Device will do required start up chores and then start to listen
140 // to new commands.
141 // TODO(antonm): Consider moving into some other class.
142 void StartDevice(chromeos::ErrorPtr* error,
143 const base::TimeDelta& retry_delay);
144
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700145 // Saves the device registration to cache.
146 bool Save() const;
147
Christopher Wileyc900e482015-02-15 15:42:04 -0800148 // Checks whether we have credentials generated during registration.
149 bool HaveRegistrationCredentials(chromeos::ErrorPtr* error);
150
David Zeuthen390d1912015-03-03 14:54:48 -0500151 // If we currently have an access token and it doesn't like like it
152 // has expired yet, returns true immediately. Otherwise calls
153 // RefreshAccessToken().
154 bool MaybeRefreshAccessToken(chromeos::ErrorPtr* error);
155
156 // Forcibly refreshes the access token.
157 bool RefreshAccessToken(chromeos::ErrorPtr* error);
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700158
Nathan Bullock24d189f2015-02-26 13:09:18 -0500159 // Parse the OAuth response, and sets registration status to
160 // kInvalidCredentials if our registration is no longer valid.
161 std::unique_ptr<base::DictionaryValue> ParseOAuthResponse(
162 const chromeos::http::Response* response, chromeos::ErrorPtr* error);
163
Nathan Bullockbea91132015-02-19 09:13:33 -0500164 // This attempts to open the XMPP channel. The XMPP channel needs to be
165 // restarted anytime the access_token is refreshed.
166 void StartXmpp();
167
Anton Muhinac661ab2014-10-03 20:29:48 +0400168 using CloudRequestCallback =
169 base::Callback<void(const base::DictionaryValue&)>;
Alex Vakulenko0357c032015-01-06 16:32:31 -0800170 using CloudRequestErrorCallback =
171 base::Callback<void(const chromeos::Error* error)>;
Anton Muhinac661ab2014-10-03 20:29:48 +0400172
173 // Do a HTTPS request to cloud services.
174 // Handles many cases like reauthorization, 5xx HTTP response codes
175 // and device removal. It is a recommended way to do cloud API
176 // requests.
177 // TODO(antonm): Consider moving into some other class.
178 void DoCloudRequest(
Anton Muhin233d2ee2014-10-22 15:16:24 +0400179 const std::string& method,
Anton Muhinac661ab2014-10-03 20:29:48 +0400180 const std::string& url,
181 const base::DictionaryValue* body,
Alex Vakulenko0357c032015-01-06 16:32:31 -0800182 const CloudRequestCallback& success_callback,
183 const CloudRequestErrorCallback& error_callback);
Anton Muhinac661ab2014-10-03 20:29:48 +0400184
Christopher Wileyba983c82015-03-05 16:32:23 -0800185 void UpdateDeviceResource(const base::Closure& on_success,
186 const CloudRequestErrorCallback& on_failure);
Anton Muhinc635c592014-10-28 21:48:08 +0400187
Christopher Wileyba983c82015-03-05 16:32:23 -0800188 void FetchCommands(
189 const base::Callback<void(const base::ListValue&)>& on_success,
190 const CloudRequestErrorCallback& on_failure);
Anton Muhinc635c592014-10-28 21:48:08 +0400191
Christopher Wileyba983c82015-03-05 16:32:23 -0800192 void AbortLimboCommands(const base::Closure& callback,
Anton Muhinc635c592014-10-28 21:48:08 +0400193 const base::ListValue& commands);
194
195 void PeriodicallyPollCommands();
196
Anton Muhind07e2062014-10-27 10:53:29 +0400197 void PublishCommands(const base::ListValue& commands);
198
Anton Muhinb8315622014-11-20 03:17:05 +0400199 void PublishStateUpdates();
200
David Zeuthend0db55c2015-02-12 14:47:35 -0500201 // Looks up the value for parameter with name |param_name| in
202 // |params|, supplying a default value if one is available and
203 // |params| doesn't have a value for |param_name|. The value will be
204 // returned in |param_value|. Returns |true| if a value was set
205 // (either from |params| or a default), |false| otherwise and
206 // |error| will be set.
207 bool GetParamValue(
Anton Muhin332df192014-11-22 05:59:14 +0400208 const std::map<std::string, std::string>& params,
209 const std::string& param_name,
David Zeuthend0db55c2015-02-12 14:47:35 -0500210 std::string* param_value,
211 chromeos::ErrorPtr* error);
Anton Muhin332df192014-11-22 05:59:14 +0400212
Anton Muhind8d32162014-10-02 20:37:00 +0400213 // Builds Cloud API devices collection REST resouce which matches
214 // current state of the device including command definitions
215 // for all supported commands and current device state.
216 std::unique_ptr<base::DictionaryValue> BuildDeviceResource(
217 chromeos::ErrorPtr* error);
218
Christopher Wileyc900e482015-02-15 15:42:04 -0800219 void SetRegistrationStatus(RegistrationStatus new_status);
Vitaly Buka620bd7e2015-03-16 01:07:01 -0700220 void SetDeviceId(const std::string& device_id);
Christopher Wileyc900e482015-02-15 15:42:04 -0800221
Nathan Bullockd9e0bcd2015-02-11 11:36:39 -0500222 std::unique_ptr<XmppClient> xmpp_client_;
223 base::MessageLoopForIO::FileDescriptorWatcher fd_watcher_;
224
Anton Muhin332df192014-11-22 05:59:14 +0400225 std::string client_id_;
226 std::string client_secret_;
227 std::string api_key_;
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700228 std::string refresh_token_;
229 std::string device_id_;
230 std::string device_robot_account_;
Anton Muhin332df192014-11-22 05:59:14 +0400231 std::string oauth_url_;
232 std::string service_url_;
Anton Muhin332df192014-11-22 05:59:14 +0400233 std::string device_kind_;
234 std::string name_;
235 std::string display_name_;
236 std::string description_;
237 std::string location_;
Vitaly Buka6522ab62015-02-19 10:26:31 -0800238 std::string model_id_;
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700239
Nathan Bullockd9e0bcd2015-02-11 11:36:39 -0500240 // Transient data
241 std::string access_token_;
242 base::Time access_token_expiration_;
Nathan Bullockd9e0bcd2015-02-11 11:36:39 -0500243
Alex Vakulenkoa3062c52014-04-21 17:05:51 -0700244 // HTTP transport used for communications.
Alex Vakulenkocca20932014-08-20 17:35:12 -0700245 std::shared_ptr<chromeos::http::Transport> transport_;
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700246 // Serialization interface to save and load device registration info.
247 std::shared_ptr<StorageInterface> storage_;
Alex Vakulenko1f30a622014-07-23 11:13:15 -0700248 // Global command manager.
249 std::shared_ptr<CommandManager> command_manager_;
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700250 // Device state manager.
Anton Muhinb8315622014-11-20 03:17:05 +0400251 std::shared_ptr<StateManager> state_manager_;
Alex Vakulenkoa3062c52014-04-21 17:05:51 -0700252
Anton Muhin332df192014-11-22 05:59:14 +0400253 // Buffet configuration.
254 std::unique_ptr<chromeos::KeyValueStore> config_store_;
255
Christopher Wileyc900e482015-02-15 15:42:04 -0800256 // Tracks our current registration status.
Vitaly Bukab055f152015-03-12 13:41:43 -0700257 RegistrationStatus registration_status_{RegistrationStatus::kUnconfigured};
Vitaly Buka7ad8ffb2015-03-20 09:46:57 -0700258 base::Closure on_status_changed_;
Christopher Wileyc900e482015-02-15 15:42:04 -0800259
Alex Vakulenko8e34d392014-04-29 11:02:56 -0700260 friend class TestHelper;
Christopher Wileycd419662015-02-06 17:51:43 -0800261 base::WeakPtrFactory<DeviceRegistrationInfo> weak_factory_{this};
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700262 DISALLOW_COPY_AND_ASSIGN(DeviceRegistrationInfo);
263};
264
265} // namespace buffet
266
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700267#endif // BUFFET_DEVICE_REGISTRATION_INFO_H_