Skip to content

Commit 03641d6

Browse files
smilesa-maurice
authored andcommitted
Added instance ID token fetch.
Also, improved test coverage of check-in. PiperOrigin-RevId: 248609129
1 parent 491f22f commit 03641d6

File tree

4 files changed

+130
-2
lines changed

4 files changed

+130
-2
lines changed

app/instance_id/instance_id_desktop_impl.cc

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#include <assert.h>
1818

1919
#include "app/instance_id/iid_data_generated.h"
20+
#include "app/rest/util.h"
21+
#include "app/rest/www_form_url_encoded.h"
2022
#include "app/src/app_identifier.h"
2123
#include "app/src/base64.h"
2224
#include "app/src/cleanup_notifier.h"
@@ -54,9 +56,13 @@ InstanceIdDesktopImpl::InstanceIdDesktopImpl(App* app)
5456
logging_id_(rand()), // NOLINT
5557
ios_device_model_("iPhone 8" /* TODO */),
5658
ios_device_version_("8.0" /* TODO */),
59+
app_version_("1.2.3" /* TODO */),
60+
os_version_("freedos-10.0.0" /* TODO */),
61+
platform_(0),
5762
network_operation_complete_(0),
5863
terminating_(false) {
5964
rest::InitTransportCurl();
65+
rest::util::Initialize();
6066
transport_.reset(new rest::TransportCurl());
6167
(void)kInstanceIdUrl; // TODO(smiles): Remove this when registration is in.
6268

@@ -107,6 +113,7 @@ InstanceIdDesktopImpl::~InstanceIdDesktopImpl() {
107113
scheduler_.CancelAllAndShutdownWorkerThread();
108114

109115
rest::CleanupTransportCurl();
116+
rest::util::Terminate();
110117
{
111118
MutexLock lock(instance_id_by_app_mutex_);
112119
auto it = instance_id_by_app_.find(app_);
@@ -394,6 +401,7 @@ bool InstanceIdDesktopImpl::InitialOrRefreshCheckin() {
394401
rest::Request* request = &network_operation_->request;
395402
request->set_url(kCheckinUrl);
396403
request->set_method(rest::util::kPost);
404+
request->add_header(rest::util::kAccept, rest::util::kApplicationJson);
397405
request->add_header(rest::util::kContentType, rest::util::kApplicationJson);
398406
network_operation_->Perform(transport_.get());
399407
}
@@ -426,8 +434,8 @@ bool InstanceIdDesktopImpl::InitialOrRefreshCheckin() {
426434
network_operation_.reset(nullptr);
427435
return false;
428436
}
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();
431439
checkin_data_.digest = root["digest"].AsString().c_str();
432440
checkin_data_.last_checkin_time_ms = firebase::internal::GetTimestamp();
433441
network_operation_.reset(nullptr);
@@ -463,6 +471,102 @@ std::string InstanceIdDesktopImpl::GenerateAppId() {
463471
return ""; // Error encoding.
464472
}
465473

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+
466570
} // namespace internal
467571
} // namespace instance_id
468572
} // namespace firebase

app/instance_id/instance_id_desktop_impl.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,16 @@ class InstanceIdDesktopImpl {
207207
// randomness, then base64-encoded until golden brown.
208208
std::string GenerateAppId();
209209

210+
// Find cached token for a scope.
211+
std::string FindCachedToken(const char* scope);
212+
213+
// Clear a token for a scope.
214+
void DeleteCachedToken(const char* scope);
215+
216+
// Fetch a new token. Scope can be either "FCM" or "*" for remote config
217+
// and other users.
218+
bool FetchToken(const char* scope);
219+
210220
// Used to wait for async storage functions to finish.
211221
Semaphore storage_semaphore_;
212222

@@ -234,6 +244,12 @@ class InstanceIdDesktopImpl {
234244
std::string ios_device_model_;
235245
// iOS device version.
236246
std::string ios_device_version_;
247+
// Application version.
248+
std::string app_version_;
249+
// Operating system version.
250+
std::string os_version_;
251+
// Platform requesting a token. 0 = UNKNOWN
252+
int platform_;
237253

238254
// Performs network operations for this object.
239255
UniquePtr<rest::Transport> transport_;

app/rest/util.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,12 @@ namespace rest {
3333
namespace util {
3434

3535
const char kHttpHeaderSeparator = ':';
36+
const char kAccept[] = "Accept";
37+
const char kAuthorization[] = "Authorization";
3638
const char kContentType[] = "Content-Type";
3739
const char kApplicationJson[] = "application/json";
40+
const char kApplicationWwwFormUrlencoded[] =
41+
"application/x-www-form-urlencoded";
3842
const char kDate[] = "Date";
3943
const char kCrLf[] = "\r\n";
4044
const char kGet[] = "GET";

app/rest/util.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define FIREBASE_APP_CLIENT_CPP_REST_UTIL_H_
1919

2020
#include <string>
21+
2122
#include "app/src/include/firebase/variant.h"
2223
#include "app/src/mutex.h"
2324
#include "flatbuffers/idl.h"
@@ -29,8 +30,11 @@ namespace util {
2930
// The separator between field name and value in HTTP headers.
3031
extern const char kHttpHeaderSeparator;
3132
// String literals for a few common header strings (names and values).
33+
extern const char kAccept[];
34+
extern const char kAuthorization[];
3235
extern const char kContentType[];
3336
extern const char kApplicationJson[];
37+
extern const char kApplicationWwwFormUrlencoded[];
3438
extern const char kDate[];
3539
// The CRLF literal.
3640
extern const char kCrLf[];

0 commit comments

Comments
 (0)