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> 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 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. 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> 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 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 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 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 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 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 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 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 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. 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. 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 352 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 361 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 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 423 PrivetHandler::~PrivetHandler() { 424 for (const auto& req : update_requests_) 425 ReplyToUpdateRequest(req.callback); 426 } 427 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 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 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 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 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 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 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 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 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 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 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 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 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 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, ®istration)) { 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 810 void PrivetHandler::HandleSetupStatus(const base::DictionaryValue&, 811 const UserInfo& user_info, 812 const RequestCallback& callback) { 813 ReplyWithSetupStatus(callback); 814 } 815 816 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 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 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 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 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 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 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 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 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 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 1031 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 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