|
17 | 17 | #include <assert.h>
|
18 | 18 |
|
19 | 19 | #include "app/instance_id/iid_data_generated.h"
|
| 20 | +#include "app/rest/util.h" |
| 21 | +#include "app/rest/www_form_url_encoded.h" |
20 | 22 | #include "app/src/app_identifier.h"
|
21 | 23 | #include "app/src/base64.h"
|
22 | 24 | #include "app/src/cleanup_notifier.h"
|
@@ -54,9 +56,13 @@ InstanceIdDesktopImpl::InstanceIdDesktopImpl(App* app)
|
54 | 56 | logging_id_(rand()), // NOLINT
|
55 | 57 | ios_device_model_("iPhone 8" /* TODO */),
|
56 | 58 | ios_device_version_("8.0" /* TODO */),
|
| 59 | + app_version_("1.2.3" /* TODO */), |
| 60 | + os_version_("freedos-10.0.0" /* TODO */), |
| 61 | + platform_(0), |
57 | 62 | network_operation_complete_(0),
|
58 | 63 | terminating_(false) {
|
59 | 64 | rest::InitTransportCurl();
|
| 65 | + rest::util::Initialize(); |
60 | 66 | transport_.reset(new rest::TransportCurl());
|
61 | 67 | (void)kInstanceIdUrl; // TODO(smiles): Remove this when registration is in.
|
62 | 68 |
|
@@ -107,6 +113,7 @@ InstanceIdDesktopImpl::~InstanceIdDesktopImpl() {
|
107 | 113 | scheduler_.CancelAllAndShutdownWorkerThread();
|
108 | 114 |
|
109 | 115 | rest::CleanupTransportCurl();
|
| 116 | + rest::util::Terminate(); |
110 | 117 | {
|
111 | 118 | MutexLock lock(instance_id_by_app_mutex_);
|
112 | 119 | auto it = instance_id_by_app_.find(app_);
|
@@ -394,6 +401,7 @@ bool InstanceIdDesktopImpl::InitialOrRefreshCheckin() {
|
394 | 401 | rest::Request* request = &network_operation_->request;
|
395 | 402 | request->set_url(kCheckinUrl);
|
396 | 403 | request->set_method(rest::util::kPost);
|
| 404 | + request->add_header(rest::util::kAccept, rest::util::kApplicationJson); |
397 | 405 | request->add_header(rest::util::kContentType, rest::util::kApplicationJson);
|
398 | 406 | network_operation_->Perform(transport_.get());
|
399 | 407 | }
|
@@ -426,8 +434,8 @@ bool InstanceIdDesktopImpl::InitialOrRefreshCheckin() {
|
426 | 434 | network_operation_.reset(nullptr);
|
427 | 435 | return false;
|
428 | 436 | }
|
429 |
| - checkin_data_.device_id = root["android_id"].AsString().c_str(); |
430 |
| - checkin_data_.security_token = root["security_token"].AsString().c_str(); |
| 437 | + checkin_data_.device_id = root["android_id"].ToString(); |
| 438 | + checkin_data_.security_token = root["security_token"].ToString(); |
431 | 439 | checkin_data_.digest = root["digest"].AsString().c_str();
|
432 | 440 | checkin_data_.last_checkin_time_ms = firebase::internal::GetTimestamp();
|
433 | 441 | network_operation_.reset(nullptr);
|
@@ -463,6 +471,102 @@ std::string InstanceIdDesktopImpl::GenerateAppId() {
|
463 | 471 | return ""; // Error encoding.
|
464 | 472 | }
|
465 | 473 |
|
| 474 | +std::string InstanceIdDesktopImpl::FindCachedToken(const char* scope) { |
| 475 | + auto cached_token = tokens_.find(scope); |
| 476 | + if (cached_token == tokens_.end()) return std::string(); |
| 477 | + return cached_token->second; |
| 478 | +} |
| 479 | + |
| 480 | +void InstanceIdDesktopImpl::DeleteCachedToken(const char* scope) { |
| 481 | + auto cached_token = tokens_.find(scope); |
| 482 | + if (cached_token != tokens_.end()) { |
| 483 | + tokens_.erase(cached_token); |
| 484 | + } |
| 485 | +} |
| 486 | + |
| 487 | +bool InstanceIdDesktopImpl::FetchToken(const char* scope) { |
| 488 | + if (terminating_ || !InitialOrRefreshCheckin()) return false; |
| 489 | + |
| 490 | + // If we already have a token, don't refresh. |
| 491 | + std::string token = FindCachedToken(scope); |
| 492 | + if (!token.empty()) return true; |
| 493 | + |
| 494 | + const AppOptions& app_options = app_->options(); |
| 495 | + request_buffer_.clear(); |
| 496 | + rest::WwwFormUrlEncoded form(&request_buffer_); |
| 497 | + form.Add("sender", app_options.messaging_sender_id()); |
| 498 | + form.Add("app", app_options.package_name()); |
| 499 | + form.Add("app_ver", app_version_.c_str()); |
| 500 | + form.Add("device", checkin_data_.device_id.c_str()); |
| 501 | + // NOTE: We're not providing the Xcliv field here as we don't support |
| 502 | + // FCM on desktop yet. |
| 503 | + form.Add("X-scope", scope); |
| 504 | + form.Add("X-subtype", app_options.messaging_sender_id()); |
| 505 | + form.Add("X-osv", os_version_.c_str()); |
| 506 | + form.Add("plat", flatbuffers::NumToString(platform_).c_str()); |
| 507 | + form.Add("app_id", instance_id_.c_str()); |
| 508 | + |
| 509 | + // Send request to the server then wait for the response or for the request |
| 510 | + // to be canceled by another thread. |
| 511 | + { |
| 512 | + MutexLock lock(network_operation_mutex_); |
| 513 | + network_operation_.reset( |
| 514 | + new NetworkOperation(request_buffer_, &network_operation_complete_)); |
| 515 | + rest::Request* request = &network_operation_->request; |
| 516 | + request->set_url(kInstanceIdUrl); |
| 517 | + request->set_method(rest::util::kPost); |
| 518 | + request->add_header(rest::util::kAccept, |
| 519 | + rest::util::kApplicationWwwFormUrlencoded); |
| 520 | + request->add_header(rest::util::kContentType, |
| 521 | + rest::util::kApplicationWwwFormUrlencoded); |
| 522 | + request->add_header(rest::util::kAuthorization, |
| 523 | + (std::string("AidLogin ") + checkin_data_.device_id + |
| 524 | + std::string(":") + checkin_data_.security_token) |
| 525 | + .c_str()); |
| 526 | + network_operation_->Perform(transport_.get()); |
| 527 | + } |
| 528 | + network_operation_complete_.Wait(); |
| 529 | + |
| 530 | + { |
| 531 | + MutexLock lock(network_operation_mutex_); |
| 532 | + assert(network_operation_.get()); |
| 533 | + const rest::Response& response = network_operation_->response; |
| 534 | + // Check for errors |
| 535 | + if (response.status() != rest::util::HttpSuccess) { |
| 536 | + LogError("Instance ID token fetch failed with response %d '%s'", |
| 537 | + response.status(), response.GetBody()); |
| 538 | + network_operation_.reset(nullptr); |
| 539 | + return false; |
| 540 | + } |
| 541 | + // Parse the response. |
| 542 | + auto form_data = rest::WwwFormUrlEncoded::Parse(response.GetBody()); |
| 543 | + |
| 544 | + std::string error; |
| 545 | + |
| 546 | + // Search the response for a token or an error. |
| 547 | + for (size_t i = 0; i < form_data.size(); ++i) { |
| 548 | + const auto& item = form_data[i]; |
| 549 | + if (item.key == "token") { |
| 550 | + token = item.value; |
| 551 | + } else if (item.key == "Error") { |
| 552 | + error = item.value; |
| 553 | + } |
| 554 | + } |
| 555 | + |
| 556 | + if (token.empty()) { |
| 557 | + LogError( |
| 558 | + "No token returned in instance ID token fetch. " |
| 559 | + "Responded with '%s'", |
| 560 | + response.GetBody()); |
| 561 | + return false; |
| 562 | + } |
| 563 | + |
| 564 | + // Cache the token. |
| 565 | + tokens_[scope] = token; |
| 566 | + } |
| 567 | + return true; |
| 568 | +} |
| 569 | + |
466 | 570 | } // namespace internal
|
467 | 571 | } // namespace instance_id
|
468 | 572 | } // namespace firebase
|
0 commit comments