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 #include "src/privet/privet_handler.h"
6 
7 #include <algorithm>
8 #include <memory>
9 #include <set>
10 #include <string>
11 #include <utility>
12 
13 #include <base/bind.h>
14 #include <base/location.h>
15 #include <base/strings/stringprintf.h>
16 #include <base/values.h>
17 #include <weave/enum_to_string.h>
18 #include <weave/provider/task_runner.h>
19 
20 #include "src/config.h"
21 #include "src/http_constants.h"
22 #include "src/privet/cloud_delegate.h"
23 #include "src/privet/constants.h"
24 #include "src/privet/device_delegate.h"
25 #include "src/privet/device_ui_kind.h"
26 #include "src/privet/security_delegate.h"
27 #include "src/privet/wifi_delegate.h"
28 #include "src/string_utils.h"
29 #include "src/utils.h"
30 
31 namespace weave {
32 namespace privet {
33 
34 namespace {
35 
36 const char kInfoVersionKey[] = "version";
37 const char kInfoVersionValue[] = "3.0";
38 
39 const char kNameKey[] = "name";
40 const char kDescrptionKey[] = "description";
41 const char kLocationKey[] = "location";
42 
43 const char kGcdKey[] = "gcd";
44 const char kWifiKey[] = "wifi";
45 const char kStatusKey[] = "status";
46 const char kErrorKey[] = "error";
47 const char kCryptoKey[] = "crypto";
48 const char kStatusErrorValue[] = "error";
49 
50 const char kInfoIdKey[] = "id";
51 const char kInfoServicesKey[] = "services";
52 
53 const char kInfoEndpointsKey[] = "endpoints";
54 const char kInfoEndpointsHttpPortKey[] = "httpPort";
55 const char kInfoEndpointsHttpUpdatePortKey[] = "httpUpdatesPort";
56 const char kInfoEndpointsHttpsPortKey[] = "httpsPort";
57 const char kInfoEndpointsHttpsUpdatePortKey[] = "httpsUpdatesPort";
58 
59 const char kInfoModelIdKey[] = "modelManifestId";
60 const char kInfoModelManifestKey[] = "basicModelManifest";
61 const char kInfoManifestUiDeviceKind[] = "uiDeviceKind";
62 const char kInfoManifestOemName[] = "oemName";
63 const char kInfoManifestModelName[] = "modelName";
64 
65 const char kInfoAuthenticationKey[] = "authentication";
66 
67 const char kInfoAuthAnonymousMaxScopeKey[] = "anonymousMaxScope";
68 
69 const char kInfoWifiCapabilitiesKey[] = "capabilities";
70 const char kInfoWifiSsidKey[] = "ssid";
71 const char kInfoWifiHostedSsidKey[] = "hostedSsid";
72 const char kInfoTimeKey[] = "time";
73 const char kInfoSessionIdKey[] = "sessionId";
74 
75 const char kPairingKey[] = "pairing";
76 const char kPairingSessionIdKey[] = "sessionId";
77 const char kPairingDeviceCommitmentKey[] = "deviceCommitment";
78 const char kPairingClientCommitmentKey[] = "clientCommitment";
79 const char kPairingFingerprintKey[] = "certFingerprint";
80 const char kPairingSignatureKey[] = "certSignature";
81 
82 const char kAuthModeKey[] = "mode";
83 const char kAuthCodeKey[] = "authCode";
84 const char kAuthRequestedScopeKey[] = "requestedScope";
85 const char kAuthScopeAutoValue[] = "auto";
86 
87 const char kAuthAccessTokenKey[] = "accessToken";
88 const char kAuthTokenTypeKey[] = "tokenType";
89 const char kAuthExpiresInKey[] = "expiresIn";
90 const char kAuthScopeKey[] = "scope";
91 const char kAuthClientTokenKey[] = "clientToken";
92 
93 const char kAuthorizationHeaderPrefix[] = "Privet";
94 
95 const char kErrorDebugInfoKey[] = "debugInfo";
96 
97 const char kSetupStartSsidKey[] = "ssid";
98 const char kSetupStartPassKey[] = "passphrase";
99 const char kSetupStartTicketIdKey[] = "ticketId";
100 const char kSetupStartUserKey[] = "user";
101 
102 const char kFingerprintKey[] = "fingerprint";
103 const char kStateKey[] = "state";
104 const char kCommandsKey[] = "commands";
105 const char kTraitsKey[] = "traits";
106 const char kComponentsKey[] = "components";
107 const char kCommandsIdKey[] = "id";
108 const char kPathKey[] = "path";
109 const char kFilterKey[] = "filter";
110 
111 const char kStateFingerprintKey[] = "stateFingerprint";
112 const char kCommandsFingerprintKey[] = "commandsFingerprint";
113 const char kTraitsFingerprintKey[] = "traitsFingerprint";
114 const char kComponentsFingerprintKey[] = "componentsFingerprint";
115 const char kWaitTimeoutKey[] = "waitTimeout";
116 
117 const char kInvalidParamValueFormat[] = "Invalid parameter: '%s'='%s'";
118 
119 template <class Container>
ToValue(const Container & list)120 std::unique_ptr<base::ListValue> ToValue(const Container& list) {
121   std::unique_ptr<base::ListValue> value_list(new base::ListValue());
122   for (const std::string& val : list)
123     value_list->AppendString(val);
124   return value_list;
125 }
126 
127 struct {
128   const char* const reason;
129   int code;
130 } kReasonToCode[] = {
131     {errors::kInvalidClientCommitment, http::kForbidden},
132     {errors::kInvalidFormat, http::kBadRequest},
133     {errors::kMissingAuthorization, http::kDenied},
134     {errors::kInvalidAuthorization, http::kDenied},
135     {errors::kInvalidAuthorizationScope, http::kForbidden},
136     {errors::kAuthorizationExpired, http::kForbidden},
137     {errors::kCommitmentMismatch, http::kForbidden},
138     {errors::kUnknownSession, http::kNotFound},
139     {errors::kInvalidAuthCode, http::kForbidden},
140     {errors::kInvalidAuthMode, http::kBadRequest},
141     {errors::kInvalidRequestedScope, http::kBadRequest},
142     {errors::kAccessDenied, http::kForbidden},
143     {errors::kInvalidParams, http::kBadRequest},
144     {errors::kSetupUnavailable, http::kBadRequest},
145     {errors::kDeviceBusy, http::kServiceUnavailable},
146     {errors::kInvalidState, http::kInternalServerError},
147     {errors::kNotFound, http::kNotFound},
148     {errors::kNotImplemented, http::kNotSupported},
149     {errors::kAlreadyClaimed, http::kDenied},
150 };
151 
GetAuthTokenFromAuthHeader(const std::string & auth_header)152 std::string GetAuthTokenFromAuthHeader(const std::string& auth_header) {
153   return SplitAtFirst(auth_header, " ", true).second;
154 }
155 
156 // Creates JSON similar to GCD server error format.
ErrorToJson(const Error & error)157 std::unique_ptr<base::DictionaryValue> ErrorToJson(const Error& error) {
158   std::unique_ptr<base::DictionaryValue> output{ErrorInfoToJson(error)};
159 
160   // Optional debug information.
161   std::unique_ptr<base::ListValue> errors{new base::ListValue};
162   for (const Error* it = &error; it; it = it->GetInnerError()) {
163     std::unique_ptr<base::DictionaryValue> inner{ErrorInfoToJson(*it)};
164     tracked_objects::Location location{it->GetLocation().function_name.c_str(),
165                                        it->GetLocation().file_name.c_str(),
166                                        it->GetLocation().line_number, nullptr};
167     inner->SetString(kErrorDebugInfoKey, location.ToString());
168     errors->Append(inner.release());
169   }
170   output->Set(kErrorDebugInfoKey, errors.release());
171   return output;
172 }
173 
174 template <class T>
SetStateProperties(const T & state,base::DictionaryValue * parent)175 void SetStateProperties(const T& state, base::DictionaryValue* parent) {
176   if (!state.error()) {
177     parent->SetString(kStatusKey, EnumToString(state.status()));
178     return;
179   }
180   parent->SetString(kStatusKey, kStatusErrorValue);
181   parent->Set(kErrorKey, ErrorToJson(*state.error()).release());
182 }
183 
ReturnError(const Error & error,const PrivetHandler::RequestCallback & callback)184 void ReturnError(const Error& error,
185                  const PrivetHandler::RequestCallback& callback) {
186   int code = http::kInternalServerError;
187   for (const auto& it : kReasonToCode) {
188     if (error.HasError(it.reason)) {
189       code = it.code;
190       break;
191     }
192   }
193   std::unique_ptr<base::DictionaryValue> output{new base::DictionaryValue};
194   output->Set(kErrorKey, ErrorToJson(error).release());
195   callback.Run(code, *output);
196 }
197 
OnCommandRequestSucceeded(const PrivetHandler::RequestCallback & callback,const base::DictionaryValue & output,ErrorPtr error)198 void OnCommandRequestSucceeded(const PrivetHandler::RequestCallback& callback,
199                                const base::DictionaryValue& output,
200                                ErrorPtr error) {
201   if (!error)
202     return callback.Run(http::kOk, output);
203 
204   if (error->HasError("unknown_command")) {
205     Error::AddTo(&error, FROM_HERE, errors::kNotFound, "Unknown command ID");
206     return ReturnError(*error, callback);
207   }
208   if (error->HasError("access_denied")) {
209     Error::AddTo(&error, FROM_HERE, errors::kAccessDenied, error->GetMessage());
210     return ReturnError(*error, callback);
211   }
212   return ReturnError(*error, callback);
213 }
214 
CreateManifestSection(const CloudDelegate & cloud)215 std::unique_ptr<base::DictionaryValue> CreateManifestSection(
216     const CloudDelegate& cloud) {
217   std::unique_ptr<base::DictionaryValue> manifest(new base::DictionaryValue());
218   manifest->SetString(kInfoManifestUiDeviceKind,
219                       GetDeviceUiKind(cloud.GetModelId()));
220   manifest->SetString(kInfoManifestOemName, cloud.GetOemName());
221   manifest->SetString(kInfoManifestModelName, cloud.GetModelName());
222   return manifest;
223 }
224 
CreateEndpointsSection(const DeviceDelegate & device)225 std::unique_ptr<base::DictionaryValue> CreateEndpointsSection(
226     const DeviceDelegate& device) {
227   std::unique_ptr<base::DictionaryValue> endpoints(new base::DictionaryValue());
228   auto http_endpoint = device.GetHttpEnpoint();
229   endpoints->SetInteger(kInfoEndpointsHttpPortKey, http_endpoint.first);
230   endpoints->SetInteger(kInfoEndpointsHttpUpdatePortKey, http_endpoint.second);
231 
232   auto https_endpoint = device.GetHttpsEnpoint();
233   endpoints->SetInteger(kInfoEndpointsHttpsPortKey, https_endpoint.first);
234   endpoints->SetInteger(kInfoEndpointsHttpsUpdatePortKey,
235                         https_endpoint.second);
236 
237   return endpoints;
238 }
239 
CreateInfoAuthSection(const SecurityDelegate & security,AuthScope anonymous_max_scope)240 std::unique_ptr<base::DictionaryValue> CreateInfoAuthSection(
241     const SecurityDelegate& security,
242     AuthScope anonymous_max_scope) {
243   std::unique_ptr<base::DictionaryValue> auth(new base::DictionaryValue());
244 
245   auth->SetString(kInfoAuthAnonymousMaxScopeKey,
246                   EnumToString(anonymous_max_scope));
247 
248   std::unique_ptr<base::ListValue> pairing_types(new base::ListValue());
249   for (PairingType type : security.GetPairingTypes())
250     pairing_types->AppendString(EnumToString(type));
251   auth->Set(kPairingKey, pairing_types.release());
252 
253   std::unique_ptr<base::ListValue> auth_types(new base::ListValue());
254   for (AuthType type : security.GetAuthTypes())
255     auth_types->AppendString(EnumToString(type));
256   auth->Set(kAuthModeKey, auth_types.release());
257 
258   std::unique_ptr<base::ListValue> crypto_types(new base::ListValue());
259   for (CryptoType type : security.GetCryptoTypes())
260     crypto_types->AppendString(EnumToString(type));
261   auth->Set(kCryptoKey, crypto_types.release());
262 
263   return auth;
264 }
265 
CreateWifiSection(const WifiDelegate & wifi)266 std::unique_ptr<base::DictionaryValue> CreateWifiSection(
267     const WifiDelegate& wifi) {
268   std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue());
269 
270   std::unique_ptr<base::ListValue> capabilities(new base::ListValue());
271   for (WifiType type : wifi.GetTypes())
272     capabilities->AppendString(EnumToString(type));
273   result->Set(kInfoWifiCapabilitiesKey, capabilities.release());
274 
275   result->SetString(kInfoWifiSsidKey, wifi.GetCurrentlyConnectedSsid());
276 
277   std::string hosted_ssid = wifi.GetHostedSsid();
278   const ConnectionState& state = wifi.GetConnectionState();
279   if (!hosted_ssid.empty()) {
280     DCHECK(!state.IsStatusEqual(ConnectionState::kDisabled));
281     DCHECK(!state.IsStatusEqual(ConnectionState::kOnline));
282     result->SetString(kInfoWifiHostedSsidKey, hosted_ssid);
283   }
284   SetStateProperties(state, result.get());
285   return result;
286 }
287 
CreateGcdSection(const CloudDelegate & cloud)288 std::unique_ptr<base::DictionaryValue> CreateGcdSection(
289     const CloudDelegate& cloud) {
290   std::unique_ptr<base::DictionaryValue> gcd(new base::DictionaryValue());
291   gcd->SetString(kInfoIdKey, cloud.GetCloudId());
292   SetStateProperties(cloud.GetConnectionState(), gcd.get());
293   return gcd;
294 }
295 
GetAnonymousMaxScope(const CloudDelegate & cloud,const WifiDelegate * wifi)296 AuthScope GetAnonymousMaxScope(const CloudDelegate& cloud,
297                                const WifiDelegate* wifi) {
298   if (wifi && !wifi->GetHostedSsid().empty())
299     return AuthScope::kNone;
300   return cloud.GetAnonymousMaxScope();
301 }
302 
303 // Forward-declaration.
304 std::unique_ptr<base::DictionaryValue> CloneComponentTree(
305     const base::DictionaryValue& parent,
306     const std::set<std::string>& filter);
307 
308 // Clones a particular component JSON object in a manner similar to that of
309 // DeepCopy(), except it includes only sub-objects specified in |filter| (if not
310 // empty) and has special handling for "components" sub-dictionary.
CloneComponent(const base::DictionaryValue & component,const std::set<std::string> & filter)311 std::unique_ptr<base::DictionaryValue> CloneComponent(
312     const base::DictionaryValue& component,
313     const std::set<std::string>& filter) {
314   std::unique_ptr<base::DictionaryValue> clone{new base::DictionaryValue};
315   for (base::DictionaryValue::Iterator it(component); !it.IsAtEnd();
316        it.Advance()) {
317     if (filter.empty() || filter.find(it.key()) != filter.end()) {
318       if (it.key() == kComponentsKey) {
319         // Handle "components" separately as we need to recursively clone
320         // sub-components.
321         const base::DictionaryValue* sub_components = nullptr;
322         CHECK(it.value().GetAsDictionary(&sub_components));
323         clone->SetWithoutPathExpansion(
324             it.key(), CloneComponentTree(*sub_components, filter).release());
325       } else {
326         clone->SetWithoutPathExpansion(it.key(), it.value().DeepCopy());
327       }
328     }
329   }
330   return clone;
331 }
332 
333 // Clones a dictionary containing a bunch of component JSON objects in a manner
334 // similar to that of DeepCopy(). Calls CloneComponent() on each instance of
335 // the component sub-object.
CloneComponentTree(const base::DictionaryValue & parent,const std::set<std::string> & filter)336 std::unique_ptr<base::DictionaryValue> CloneComponentTree(
337     const base::DictionaryValue& parent,
338     const std::set<std::string>& filter) {
339   std::unique_ptr<base::DictionaryValue> clone{new base::DictionaryValue};
340   for (base::DictionaryValue::Iterator it(parent); !it.IsAtEnd();
341        it.Advance()) {
342     const base::DictionaryValue* component = nullptr;
343     CHECK(it.value().GetAsDictionary(&component));
344     clone->SetWithoutPathExpansion(
345         it.key(), CloneComponent(*component, filter).release());
346   }
347   return clone;
348 }
349 
350 }  // namespace
351 
GetHttpPaths() const352 std::vector<std::string> PrivetHandler::GetHttpPaths() const {
353   std::vector<std::string> result;
354   for (const auto& pair : handlers_) {
355     if (!pair.second.https_only)
356       result.push_back(pair.first);
357   }
358   return result;
359 }
360 
GetHttpsPaths() const361 std::vector<std::string> PrivetHandler::GetHttpsPaths() const {
362   std::vector<std::string> result;
363   for (const auto& pair : handlers_)
364     result.push_back(pair.first);
365   return result;
366 }
367 
PrivetHandler(CloudDelegate * cloud,DeviceDelegate * device,SecurityDelegate * security,WifiDelegate * wifi,base::Clock * clock)368 PrivetHandler::PrivetHandler(CloudDelegate* cloud,
369                              DeviceDelegate* device,
370                              SecurityDelegate* security,
371                              WifiDelegate* wifi,
372                              base::Clock* clock)
373     : cloud_(cloud),
374       device_(device),
375       security_(security),
376       wifi_(wifi),
377       clock_(clock ? clock : &default_clock_) {
378   CHECK(cloud_);
379   CHECK(device_);
380   CHECK(security_);
381   CHECK(clock_);
382   cloud_observer_.Add(cloud_);
383 
384   AddHandler("/privet/info", &PrivetHandler::HandleInfo, AuthScope::kNone);
385   AddHandler("/privet/v3/pairing/start", &PrivetHandler::HandlePairingStart,
386              AuthScope::kNone);
387   AddHandler("/privet/v3/pairing/confirm", &PrivetHandler::HandlePairingConfirm,
388              AuthScope::kNone);
389   AddHandler("/privet/v3/pairing/cancel", &PrivetHandler::HandlePairingCancel,
390              AuthScope::kNone);
391 
392   AddSecureHandler("/privet/v3/auth", &PrivetHandler::HandleAuth,
393                    AuthScope::kNone);
394   AddSecureHandler("/privet/v3/accessControl/claim",
395                    &PrivetHandler::HandleAccessControlClaim, AuthScope::kOwner);
396   AddSecureHandler("/privet/v3/accessControl/confirm",
397                    &PrivetHandler::HandleAccessControlConfirm,
398                    AuthScope::kOwner);
399   AddSecureHandler("/privet/v3/setup/start", &PrivetHandler::HandleSetupStart,
400                    AuthScope::kManager);
401   AddSecureHandler("/privet/v3/setup/status", &PrivetHandler::HandleSetupStatus,
402                    AuthScope::kManager);
403   AddSecureHandler("/privet/v3/state", &PrivetHandler::HandleState,
404                    AuthScope::kViewer);
405   AddSecureHandler("/privet/v3/commandDefs", &PrivetHandler::HandleCommandDefs,
406                    AuthScope::kViewer);
407   AddSecureHandler("/privet/v3/commands/execute",
408                    &PrivetHandler::HandleCommandsExecute, AuthScope::kViewer);
409   AddSecureHandler("/privet/v3/commands/status",
410                    &PrivetHandler::HandleCommandsStatus, AuthScope::kViewer);
411   AddSecureHandler("/privet/v3/commands/cancel",
412                    &PrivetHandler::HandleCommandsCancel, AuthScope::kViewer);
413   AddSecureHandler("/privet/v3/commands/list",
414                    &PrivetHandler::HandleCommandsList, AuthScope::kViewer);
415   AddSecureHandler("/privet/v3/checkForUpdates",
416                    &PrivetHandler::HandleCheckForUpdates, AuthScope::kViewer);
417   AddSecureHandler("/privet/v3/traits", &PrivetHandler::HandleTraits,
418                    AuthScope::kViewer);
419   AddSecureHandler("/privet/v3/components", &PrivetHandler::HandleComponents,
420                    AuthScope::kViewer);
421 }
422 
~PrivetHandler()423 PrivetHandler::~PrivetHandler() {
424   for (const auto& req : update_requests_)
425     ReplyToUpdateRequest(req.callback);
426 }
427 
OnTraitDefsChanged()428 void PrivetHandler::OnTraitDefsChanged() {
429   ++traits_fingerprint_;
430   auto pred = [this](const UpdateRequestParameters& params) {
431     return params.traits_fingerprint == 0;
432   };
433   auto last =
434       std::partition(update_requests_.begin(), update_requests_.end(), pred);
435   for (auto p = last; p != update_requests_.end(); ++p)
436     ReplyToUpdateRequest(p->callback);
437   update_requests_.erase(last, update_requests_.end());
438 }
439 
OnStateChanged()440 void PrivetHandler::OnStateChanged() {
441   // State updates also change the component tree, so update both fingerprints.
442   ++state_fingerprint_;
443   ++components_fingerprint_;
444   auto pred = [this](const UpdateRequestParameters& params) {
445     return params.state_fingerprint == 0 && params.components_fingerprint == 0;
446   };
447   auto last =
448       std::partition(update_requests_.begin(), update_requests_.end(), pred);
449   for (auto p = last; p != update_requests_.end(); ++p)
450     ReplyToUpdateRequest(p->callback);
451   update_requests_.erase(last, update_requests_.end());
452 }
453 
OnComponentTreeChanged()454 void PrivetHandler::OnComponentTreeChanged() {
455   ++components_fingerprint_;
456   auto pred = [this](const UpdateRequestParameters& params) {
457     return params.components_fingerprint == 0;
458   };
459   auto last =
460       std::partition(update_requests_.begin(), update_requests_.end(), pred);
461   for (auto p = last; p != update_requests_.end(); ++p)
462     ReplyToUpdateRequest(p->callback);
463   update_requests_.erase(last, update_requests_.end());
464 }
465 
HandleRequest(const std::string & api,const std::string & auth_header,const base::DictionaryValue * input,const RequestCallback & callback)466 void PrivetHandler::HandleRequest(const std::string& api,
467                                   const std::string& auth_header,
468                                   const base::DictionaryValue* input,
469                                   const RequestCallback& callback) {
470   ErrorPtr error;
471   if (!input) {
472     Error::AddTo(&error, FROM_HERE, errors::kInvalidFormat, "Malformed JSON");
473     return ReturnError(*error, callback);
474   }
475   auto handler = handlers_.find(api);
476   if (handler == handlers_.end()) {
477     Error::AddTo(&error, FROM_HERE, errors::kNotFound, "Path not found");
478     return ReturnError(*error, callback);
479   }
480   if (auth_header.empty()) {
481     Error::AddTo(&error, FROM_HERE, errors::kMissingAuthorization,
482                  "Authorization header must not be empty");
483     return ReturnError(*error, callback);
484   }
485   std::string token = GetAuthTokenFromAuthHeader(auth_header);
486   if (token.empty()) {
487     Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidAuthorization,
488                        "Invalid authorization header: %s", auth_header.c_str());
489     return ReturnError(*error, callback);
490   }
491   UserInfo user_info;
492   if (token != EnumToString(AuthType::kAnonymous)) {
493     if (!security_->ParseAccessToken(token, &user_info, &error))
494       return ReturnError(*error, callback);
495   }
496 
497   if (handler->second.scope > user_info.scope()) {
498     Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidAuthorizationScope,
499                        "Scope '%s' does not allow '%s'",
500                        EnumToString(user_info.scope()).c_str(), api.c_str());
501     return ReturnError(*error, callback);
502   }
503   (this->*handler->second.handler)(*input, user_info, callback);
504 }
505 
AddHandler(const std::string & path,ApiHandler handler,AuthScope scope)506 void PrivetHandler::AddHandler(const std::string& path,
507                                ApiHandler handler,
508                                AuthScope scope) {
509   HandlerParameters params;
510   params.handler = handler;
511   params.scope = scope;
512   params.https_only = false;
513   CHECK(handlers_.insert(std::make_pair(path, params)).second);
514 }
515 
AddSecureHandler(const std::string & path,ApiHandler handler,AuthScope scope)516 void PrivetHandler::AddSecureHandler(const std::string& path,
517                                      ApiHandler handler,
518                                      AuthScope scope) {
519   HandlerParameters params;
520   params.handler = handler;
521   params.scope = scope;
522   params.https_only = true;
523   CHECK(handlers_.insert(std::make_pair(path, params)).second);
524 }
525 
HandleInfo(const base::DictionaryValue &,const UserInfo & user_info,const RequestCallback & callback)526 void PrivetHandler::HandleInfo(const base::DictionaryValue&,
527                                const UserInfo& user_info,
528                                const RequestCallback& callback) {
529   base::DictionaryValue output;
530 
531   std::string name = cloud_->GetName();
532   std::string model_id = cloud_->GetModelId();
533 
534   output.SetString(kInfoVersionKey, kInfoVersionValue);
535   output.SetString(kInfoIdKey, cloud_->GetDeviceId());
536   output.SetString(kNameKey, name);
537 
538   std::string description{cloud_->GetDescription()};
539   if (!description.empty())
540     output.SetString(kDescrptionKey, description);
541 
542   std::string location{cloud_->GetLocation()};
543   if (!location.empty())
544     output.SetString(kLocationKey, location);
545 
546   output.SetString(kInfoModelIdKey, model_id);
547   output.Set(kInfoModelManifestKey, CreateManifestSection(*cloud_).release());
548   output.Set(
549       kInfoServicesKey,
550       ToValue(std::vector<std::string>{GetDeviceUiKind(cloud_->GetModelId())})
551           .release());
552 
553   output.Set(
554       kInfoAuthenticationKey,
555       CreateInfoAuthSection(*security_, GetAnonymousMaxScope(*cloud_, wifi_))
556           .release());
557 
558   output.Set(kInfoEndpointsKey, CreateEndpointsSection(*device_).release());
559 
560   if (wifi_)
561     output.Set(kWifiKey, CreateWifiSection(*wifi_).release());
562 
563   output.Set(kGcdKey, CreateGcdSection(*cloud_).release());
564 
565   output.SetDouble(kInfoTimeKey, clock_->Now().ToJsTime());
566   output.SetString(kInfoSessionIdKey, security_->CreateSessionId());
567 
568   callback.Run(http::kOk, output);
569 }
570 
HandlePairingStart(const base::DictionaryValue & input,const UserInfo & user_info,const RequestCallback & callback)571 void PrivetHandler::HandlePairingStart(const base::DictionaryValue& input,
572                                        const UserInfo& user_info,
573                                        const RequestCallback& callback) {
574   ErrorPtr error;
575 
576   std::string pairing_str;
577   input.GetString(kPairingKey, &pairing_str);
578 
579   std::string crypto_str;
580   input.GetString(kCryptoKey, &crypto_str);
581 
582   PairingType pairing;
583   std::set<PairingType> modes = security_->GetPairingTypes();
584   if (!StringToEnum(pairing_str, &pairing) ||
585       modes.find(pairing) == modes.end()) {
586     Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidParams,
587                        kInvalidParamValueFormat, kPairingKey,
588                        pairing_str.c_str());
589     return ReturnError(*error, callback);
590   }
591 
592   CryptoType crypto;
593   std::set<CryptoType> cryptos = security_->GetCryptoTypes();
594   if (!StringToEnum(crypto_str, &crypto) ||
595       cryptos.find(crypto) == cryptos.end()) {
596     Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidParams,
597                        kInvalidParamValueFormat, kCryptoKey,
598                        crypto_str.c_str());
599     return ReturnError(*error, callback);
600   }
601 
602   std::string id;
603   std::string commitment;
604   if (!security_->StartPairing(pairing, crypto, &id, &commitment, &error))
605     return ReturnError(*error, callback);
606 
607   base::DictionaryValue output;
608   output.SetString(kPairingSessionIdKey, id);
609   output.SetString(kPairingDeviceCommitmentKey, commitment);
610   callback.Run(http::kOk, output);
611 }
612 
HandlePairingConfirm(const base::DictionaryValue & input,const UserInfo & user_info,const RequestCallback & callback)613 void PrivetHandler::HandlePairingConfirm(const base::DictionaryValue& input,
614                                          const UserInfo& user_info,
615                                          const RequestCallback& callback) {
616   std::string id;
617   input.GetString(kPairingSessionIdKey, &id);
618 
619   std::string commitment;
620   input.GetString(kPairingClientCommitmentKey, &commitment);
621 
622   std::string fingerprint;
623   std::string signature;
624   ErrorPtr error;
625   if (!security_->ConfirmPairing(id, commitment, &fingerprint, &signature,
626                                  &error)) {
627     return ReturnError(*error, callback);
628   }
629 
630   base::DictionaryValue output;
631   output.SetString(kPairingFingerprintKey, fingerprint);
632   output.SetString(kPairingSignatureKey, signature);
633   callback.Run(http::kOk, output);
634 }
635 
HandlePairingCancel(const base::DictionaryValue & input,const UserInfo & user_info,const RequestCallback & callback)636 void PrivetHandler::HandlePairingCancel(const base::DictionaryValue& input,
637                                         const UserInfo& user_info,
638                                         const RequestCallback& callback) {
639   std::string id;
640   input.GetString(kPairingSessionIdKey, &id);
641 
642   ErrorPtr error;
643   if (!security_->CancelPairing(id, &error))
644     return ReturnError(*error, callback);
645 
646   base::DictionaryValue output;
647   callback.Run(http::kOk, output);
648 }
649 
HandleAuth(const base::DictionaryValue & input,const UserInfo & user_info,const RequestCallback & callback)650 void PrivetHandler::HandleAuth(const base::DictionaryValue& input,
651                                const UserInfo& user_info,
652                                const RequestCallback& callback) {
653   ErrorPtr error;
654 
655   std::string auth_code_type;
656   AuthType auth_type{};
657   if (!input.GetString(kAuthModeKey, &auth_code_type) ||
658       !StringToEnum(auth_code_type, &auth_type)) {
659     Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidAuthMode,
660                        kInvalidParamValueFormat, kAuthModeKey,
661                        auth_code_type.c_str());
662     return ReturnError(*error, callback);
663   }
664 
665   AuthScope desired_scope = AuthScope::kOwner;
666   AuthScope acceptable_scope = AuthScope::kViewer;
667 
668   std::string requested_scope;
669   input.GetString(kAuthRequestedScopeKey, &requested_scope);
670   if (requested_scope != kAuthScopeAutoValue) {
671     if (!StringToEnum(requested_scope, &desired_scope)) {
672       Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidRequestedScope,
673                          kInvalidParamValueFormat, kAuthRequestedScopeKey,
674                          requested_scope.c_str());
675       return ReturnError(*error, callback);
676     }
677     acceptable_scope = std::max(desired_scope, acceptable_scope);
678   }
679 
680   if (auth_type == AuthType::kAnonymous)
681     desired_scope = GetAnonymousMaxScope(*cloud_, wifi_);
682 
683   std::string auth_code;
684   input.GetString(kAuthCodeKey, &auth_code);
685 
686   std::string access_token;
687   base::TimeDelta access_token_ttl;
688   AuthScope access_token_scope = AuthScope::kNone;
689   if (!security_->CreateAccessToken(auth_type, auth_code, desired_scope,
690                                     &access_token, &access_token_scope,
691                                     &access_token_ttl, &error)) {
692     return ReturnError(*error, callback);
693   }
694 
695   if (access_token_scope < acceptable_scope) {
696     Error::AddToPrintf(&error, FROM_HERE, errors::kAccessDenied,
697                        "Scope '%s' is not allowed",
698                        EnumToString(access_token_scope).c_str());
699     return ReturnError(*error, callback);
700   }
701 
702   base::DictionaryValue output;
703   output.SetString(kAuthAccessTokenKey, access_token);
704   output.SetString(kAuthTokenTypeKey, kAuthorizationHeaderPrefix);
705   output.SetInteger(kAuthExpiresInKey, access_token_ttl.InSeconds());
706   output.SetString(kAuthScopeKey, EnumToString(access_token_scope));
707 
708   callback.Run(http::kOk, output);
709 }
710 
HandleAccessControlClaim(const base::DictionaryValue & input,const UserInfo & user_info,const RequestCallback & callback)711 void PrivetHandler::HandleAccessControlClaim(const base::DictionaryValue& input,
712                                              const UserInfo& user_info,
713                                              const RequestCallback& callback) {
714   ErrorPtr error;
715   auto token = security_->ClaimRootClientAuthToken(&error);
716   if (token.empty())
717     return ReturnError(*error, callback);
718 
719   base::DictionaryValue output;
720   output.SetString(kAuthClientTokenKey, token);
721   callback.Run(http::kOk, output);
722 }
723 
HandleAccessControlConfirm(const base::DictionaryValue & input,const UserInfo & user_info,const RequestCallback & callback)724 void PrivetHandler::HandleAccessControlConfirm(
725     const base::DictionaryValue& input,
726     const UserInfo& user_info,
727     const RequestCallback& callback) {
728   ErrorPtr error;
729 
730   std::string token;
731   if (!input.GetString(kAuthClientTokenKey, &token)) {
732     Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidParams,
733                        kInvalidParamValueFormat, kAuthClientTokenKey,
734                        token.c_str());
735     return ReturnError(*error, callback);
736   }
737 
738   if (!security_->ConfirmClientAuthToken(token, &error))
739     return ReturnError(*error, callback);
740 
741   base::DictionaryValue output;
742   callback.Run(http::kOk, output);
743 }
744 
HandleSetupStart(const base::DictionaryValue & input,const UserInfo & user_info,const RequestCallback & callback)745 void PrivetHandler::HandleSetupStart(const base::DictionaryValue& input,
746                                      const UserInfo& user_info,
747                                      const RequestCallback& callback) {
748   std::string name{cloud_->GetName()};
749   input.GetString(kNameKey, &name);
750 
751   std::string description{cloud_->GetDescription()};
752   input.GetString(kDescrptionKey, &description);
753 
754   std::string location{cloud_->GetLocation()};
755   input.GetString(kLocationKey, &location);
756 
757   std::string ssid;
758   std::string passphrase;
759   std::string ticket;
760   std::string user;
761 
762   const base::DictionaryValue* wifi = nullptr;
763   if (input.GetDictionary(kWifiKey, &wifi)) {
764     if (!wifi_ || wifi_->GetTypes().empty()) {
765       ErrorPtr error;
766       Error::AddTo(&error, FROM_HERE, errors::kSetupUnavailable,
767                    "WiFi setup unavailable");
768       return ReturnError(*error, callback);
769     }
770     wifi->GetString(kSetupStartSsidKey, &ssid);
771     if (ssid.empty()) {
772       ErrorPtr error;
773       Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidParams,
774                          kInvalidParamValueFormat, kSetupStartSsidKey, "");
775       return ReturnError(*error, callback);
776     }
777     wifi->GetString(kSetupStartPassKey, &passphrase);
778   }
779 
780   const base::DictionaryValue* registration = nullptr;
781   if (input.GetDictionary(kGcdKey, &registration)) {
782     if (user_info.scope() < AuthScope::kOwner) {
783       ErrorPtr error;
784       Error::AddTo(&error, FROM_HERE, errors::kInvalidAuthorizationScope,
785                    "Only owner can register device");
786       return ReturnError(*error, callback);
787     }
788     registration->GetString(kSetupStartTicketIdKey, &ticket);
789     if (ticket.empty()) {
790       ErrorPtr error;
791       Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidParams,
792                          kInvalidParamValueFormat, kSetupStartTicketIdKey, "");
793       return ReturnError(*error, callback);
794     }
795     registration->GetString(kSetupStartUserKey, &user);
796   }
797 
798   cloud_->UpdateDeviceInfo(name, description, location);
799 
800   ErrorPtr error;
801   if (!ssid.empty() && !wifi_->ConfigureCredentials(ssid, passphrase, &error))
802     return ReturnError(*error, callback);
803 
804   if (!ticket.empty() && !cloud_->Setup(ticket, user, &error))
805     return ReturnError(*error, callback);
806 
807   ReplyWithSetupStatus(callback);
808 }
809 
HandleSetupStatus(const base::DictionaryValue &,const UserInfo & user_info,const RequestCallback & callback)810 void PrivetHandler::HandleSetupStatus(const base::DictionaryValue&,
811                                       const UserInfo& user_info,
812                                       const RequestCallback& callback) {
813   ReplyWithSetupStatus(callback);
814 }
815 
ReplyWithSetupStatus(const RequestCallback & callback) const816 void PrivetHandler::ReplyWithSetupStatus(
817     const RequestCallback& callback) const {
818   base::DictionaryValue output;
819 
820   const SetupState& state = cloud_->GetSetupState();
821   if (!state.IsStatusEqual(SetupState::kNone)) {
822     base::DictionaryValue* gcd = new base::DictionaryValue;
823     output.Set(kGcdKey, gcd);
824     SetStateProperties(state, gcd);
825     if (state.IsStatusEqual(SetupState::kSuccess))
826       gcd->SetString(kInfoIdKey, cloud_->GetCloudId());
827   }
828 
829   if (wifi_) {
830     const SetupState& state = wifi_->GetSetupState();
831     if (!state.IsStatusEqual(SetupState::kNone)) {
832       base::DictionaryValue* wifi = new base::DictionaryValue;
833       output.Set(kWifiKey, wifi);
834       SetStateProperties(state, wifi);
835       if (state.IsStatusEqual(SetupState::kSuccess))
836         wifi->SetString(kInfoWifiSsidKey, wifi_->GetCurrentlyConnectedSsid());
837     }
838   }
839 
840   callback.Run(http::kOk, output);
841 }
842 
HandleState(const base::DictionaryValue & input,const UserInfo & user_info,const RequestCallback & callback)843 void PrivetHandler::HandleState(const base::DictionaryValue& input,
844                                 const UserInfo& user_info,
845                                 const RequestCallback& callback) {
846   base::DictionaryValue output;
847   output.Set(kStateKey, cloud_->GetLegacyState().DeepCopy());
848   output.SetString(kFingerprintKey, std::to_string(state_fingerprint_));
849 
850   callback.Run(http::kOk, output);
851 }
852 
HandleTraits(const base::DictionaryValue & input,const UserInfo & user_info,const RequestCallback & callback)853 void PrivetHandler::HandleTraits(const base::DictionaryValue& input,
854                                  const UserInfo& user_info,
855                                  const RequestCallback& callback) {
856   base::DictionaryValue output;
857   output.Set(kTraitsKey, cloud_->GetTraits().DeepCopy());
858   output.SetString(kFingerprintKey, std::to_string(traits_fingerprint_));
859 
860   callback.Run(http::kOk, output);
861 }
862 
HandleComponents(const base::DictionaryValue & input,const UserInfo & user_info,const RequestCallback & callback)863 void PrivetHandler::HandleComponents(const base::DictionaryValue& input,
864                                      const UserInfo& user_info,
865                                      const RequestCallback& callback) {
866   std::string path;
867   std::set<std::string> filter;
868   std::unique_ptr<base::DictionaryValue> components;
869 
870   input.GetString(kPathKey, &path);
871   const base::ListValue* filter_items = nullptr;
872   if (input.GetList(kFilterKey, &filter_items)) {
873     for (const base::Value* value : *filter_items) {
874       std::string filter_item;
875       if (value->GetAsString(&filter_item))
876         filter.insert(filter_item);
877     }
878   }
879   const base::DictionaryValue* component = nullptr;
880   if (!path.empty()) {
881     ErrorPtr error;
882     component = cloud_->FindComponent(path, &error);
883     if (!component)
884       return ReturnError(*error, callback);
885     components.reset(new base::DictionaryValue);
886     // Get the last element of the path and use it as a dictionary key here.
887     auto parts = Split(path, ".", true, false);
888     components->Set(parts.back(), CloneComponent(*component, filter).release());
889   } else {
890     components = CloneComponentTree(cloud_->GetComponents(), filter);
891   }
892   base::DictionaryValue output;
893   output.Set(kComponentsKey, components.release());
894   output.SetString(kFingerprintKey, std::to_string(components_fingerprint_));
895 
896   callback.Run(http::kOk, output);
897 }
898 
HandleCommandDefs(const base::DictionaryValue & input,const UserInfo & user_info,const RequestCallback & callback)899 void PrivetHandler::HandleCommandDefs(const base::DictionaryValue& input,
900                                       const UserInfo& user_info,
901                                       const RequestCallback& callback) {
902   base::DictionaryValue output;
903   output.Set(kCommandsKey, cloud_->GetLegacyCommandDef().DeepCopy());
904   // Use traits fingerprint since right now we treat traits and command defs
905   // as being equivalent.
906   output.SetString(kFingerprintKey, std::to_string(traits_fingerprint_));
907 
908   callback.Run(http::kOk, output);
909 }
910 
HandleCommandsExecute(const base::DictionaryValue & input,const UserInfo & user_info,const RequestCallback & callback)911 void PrivetHandler::HandleCommandsExecute(const base::DictionaryValue& input,
912                                           const UserInfo& user_info,
913                                           const RequestCallback& callback) {
914   cloud_->AddCommand(input, user_info,
915                      base::Bind(&OnCommandRequestSucceeded, callback));
916 }
917 
HandleCommandsStatus(const base::DictionaryValue & input,const UserInfo & user_info,const RequestCallback & callback)918 void PrivetHandler::HandleCommandsStatus(const base::DictionaryValue& input,
919                                          const UserInfo& user_info,
920                                          const RequestCallback& callback) {
921   std::string id;
922   if (!input.GetString(kCommandsIdKey, &id)) {
923     ErrorPtr error;
924     Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidParams,
925                        kInvalidParamValueFormat, kCommandsIdKey, id.c_str());
926     return ReturnError(*error, callback);
927   }
928   cloud_->GetCommand(id, user_info,
929                      base::Bind(&OnCommandRequestSucceeded, callback));
930 }
931 
HandleCommandsList(const base::DictionaryValue & input,const UserInfo & user_info,const RequestCallback & callback)932 void PrivetHandler::HandleCommandsList(const base::DictionaryValue& input,
933                                        const UserInfo& user_info,
934                                        const RequestCallback& callback) {
935   cloud_->ListCommands(user_info,
936                        base::Bind(&OnCommandRequestSucceeded, callback));
937 }
938 
HandleCommandsCancel(const base::DictionaryValue & input,const UserInfo & user_info,const RequestCallback & callback)939 void PrivetHandler::HandleCommandsCancel(const base::DictionaryValue& input,
940                                          const UserInfo& user_info,
941                                          const RequestCallback& callback) {
942   std::string id;
943   if (!input.GetString(kCommandsIdKey, &id)) {
944     ErrorPtr error;
945     Error::AddToPrintf(&error, FROM_HERE, errors::kInvalidParams,
946                        kInvalidParamValueFormat, kCommandsIdKey, id.c_str());
947     return ReturnError(*error, callback);
948   }
949   cloud_->CancelCommand(id, user_info,
950                         base::Bind(&OnCommandRequestSucceeded, callback));
951 }
952 
HandleCheckForUpdates(const base::DictionaryValue & input,const UserInfo & user_info,const RequestCallback & callback)953 void PrivetHandler::HandleCheckForUpdates(const base::DictionaryValue& input,
954                                           const UserInfo& user_info,
955                                           const RequestCallback& callback) {
956   int timeout_seconds = -1;
957   input.GetInteger(kWaitTimeoutKey, &timeout_seconds);
958   base::TimeDelta timeout = device_->GetHttpRequestTimeout();
959   // Allow 10 seconds to cut the timeout short to make sure HTTP server doesn't
960   // kill the connection before we have a chance to respond. 10 seconds chosen
961   // at random here without any scientific basis for the value.
962   const base::TimeDelta safety_gap = base::TimeDelta::FromSeconds(10);
963   if (timeout != base::TimeDelta::Max()) {
964     if (timeout > safety_gap)
965       timeout -= safety_gap;
966     else
967       timeout = base::TimeDelta::FromSeconds(0);
968   }
969   if (timeout_seconds >= 0)
970     timeout = std::min(timeout, base::TimeDelta::FromSeconds(timeout_seconds));
971   if (timeout == base::TimeDelta{})
972     return ReplyToUpdateRequest(callback);
973 
974   std::string state_fingerprint;
975   std::string commands_fingerprint;
976   std::string traits_fingerprint;
977   std::string components_fingerprint;
978   input.GetString(kStateFingerprintKey, &state_fingerprint);
979   input.GetString(kCommandsFingerprintKey, &commands_fingerprint);
980   input.GetString(kTraitsFingerprintKey, &traits_fingerprint);
981   input.GetString(kComponentsFingerprintKey, &components_fingerprint);
982   const bool ignore_state = state_fingerprint.empty();
983   const bool ignore_commands = commands_fingerprint.empty();
984   const bool ignore_traits = traits_fingerprint.empty();
985   const bool ignore_components = components_fingerprint.empty();
986   // If all fingerprints are missing, nothing to wait for, return immediately.
987   if (ignore_state && ignore_commands && ignore_traits && ignore_components)
988     return ReplyToUpdateRequest(callback);
989   // If the current state fingerprint is different from the requested one,
990   // return new fingerprints.
991   if (!ignore_state && state_fingerprint != std::to_string(state_fingerprint_))
992     return ReplyToUpdateRequest(callback);
993   // If the current commands fingerprint is different from the requested one,
994   // return new fingerprints.
995   // NOTE: We are using traits fingerprint for command fingerprint as well.
996   if (!ignore_commands &&
997       commands_fingerprint != std::to_string(traits_fingerprint_)) {
998     return ReplyToUpdateRequest(callback);
999   }
1000   // If the current traits fingerprint is different from the requested one,
1001   // return new fingerprints.
1002   if (!ignore_traits &&
1003       traits_fingerprint != std::to_string(traits_fingerprint_)) {
1004     return ReplyToUpdateRequest(callback);
1005   }
1006   // If the current components fingerprint is different from the requested one,
1007   // return new fingerprints.
1008   if (!ignore_components &&
1009       components_fingerprint != std::to_string(components_fingerprint_)) {
1010     return ReplyToUpdateRequest(callback);
1011   }
1012 
1013   UpdateRequestParameters params;
1014   params.request_id = ++last_update_request_id_;
1015   params.callback = callback;
1016   params.traits_fingerprint =
1017       (ignore_traits && ignore_commands) ? 0 : traits_fingerprint_;
1018   params.state_fingerprint = ignore_state ? 0 : state_fingerprint_;
1019   params.components_fingerprint =
1020       ignore_components ? 0 : components_fingerprint_;
1021   update_requests_.push_back(params);
1022   if (timeout != base::TimeDelta::Max()) {
1023     device_->PostDelayedTask(
1024         FROM_HERE,
1025         base::Bind(&PrivetHandler::OnUpdateRequestTimeout,
1026                    weak_ptr_factory_.GetWeakPtr(), last_update_request_id_),
1027         timeout);
1028   }
1029 }
1030 
ReplyToUpdateRequest(const RequestCallback & callback) const1031 void PrivetHandler::ReplyToUpdateRequest(
1032     const RequestCallback& callback) const {
1033   base::DictionaryValue output;
1034   output.SetString(kStateFingerprintKey, std::to_string(state_fingerprint_));
1035   output.SetString(kCommandsFingerprintKey,
1036                    std::to_string(traits_fingerprint_));
1037   output.SetString(kTraitsFingerprintKey, std::to_string(traits_fingerprint_));
1038   output.SetString(kComponentsFingerprintKey,
1039                    std::to_string(components_fingerprint_));
1040   callback.Run(http::kOk, output);
1041 }
1042 
OnUpdateRequestTimeout(int update_request_id)1043 void PrivetHandler::OnUpdateRequestTimeout(int update_request_id) {
1044   auto pred = [update_request_id](const UpdateRequestParameters& params) {
1045     return params.request_id != update_request_id;
1046   };
1047   auto last =
1048       std::partition(update_requests_.begin(), update_requests_.end(), pred);
1049   for (auto p = last; p != update_requests_.end(); ++p)
1050     ReplyToUpdateRequest(p->callback);
1051   update_requests_.erase(last, update_requests_.end());
1052 }
1053 
1054 }  // namespace privet
1055 }  // namespace weave
1056