Skip to content

Commit 1573001

Browse files
jonsimantova-maurice
authored andcommitted
Add Flatbuffer for saving/loading Instance ID data.
Also adds some testing framework so we can ensure that things save/load properly (and also check whatever else is important). PiperOrigin-RevId: 248236907
1 parent 67e2aa7 commit 1573001

File tree

5 files changed

+273
-2
lines changed

5 files changed

+273
-2
lines changed

app/instance_id/iid_data.fbs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright 2019 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// The FlatBuffers schema for IID desktop saved data.
16+
17+
native_include "app/memory/unique_ptr.h";
18+
19+
namespace firebase.instance_id.internal;
20+
21+
table InstanceIdDesktopData {
22+
// Instance ID, random number generated by the client which acts as a unique
23+
// identifier when requesting tokens from the IID backend.
24+
instance_id:string;
25+
// Device ID returned by the check-in service. This is used to request tokens
26+
// from the IID service.
27+
device_id:string;
28+
// Security token returned by the check-in service. This is used to request
29+
// tokens from the IID service.
30+
security_token:string;
31+
// When the device ID and security token expire in UTC milliseconds since the
32+
// epoch.
33+
expiration_time:uint64;
34+
}
35+
36+
root_type InstanceIdDesktopData;

app/instance_id/instance_id_desktop_impl.cc

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,32 @@
1616

1717
#include <assert.h>
1818

19+
#include "app/instance_id/iid_data_generated.h"
20+
#include "app/src/app_identifier.h"
1921
#include "app/src/cleanup_notifier.h"
2022

2123
namespace firebase {
2224
namespace instance_id {
2325
namespace internal {
2426

27+
using firebase::app::secure::UserSecureManager;
28+
2529
std::map<App*, InstanceIdDesktopImpl*>
2630
InstanceIdDesktopImpl::instance_id_by_app_; // NOLINT
2731
Mutex InstanceIdDesktopImpl::instance_id_by_app_mutex_; // NOLINT
2832

29-
InstanceIdDesktopImpl::InstanceIdDesktopImpl(App* app) : app_(app) {
33+
InstanceIdDesktopImpl::InstanceIdDesktopImpl(App* app)
34+
: storage_semaphore_(0), app_(app) {
3035
future_manager().AllocFutureApi(this, kInstanceIdFnCount);
3136

37+
std::string package_name = app->options().package_name();
38+
std::string project_id = app->options().project_id();
39+
std::string app_identifier;
40+
41+
user_secure_manager_ = MakeUnique<UserSecureManager>(
42+
"iid", firebase::internal::CreateAppIdentifierFromOptions(app_->options())
43+
.c_str());
44+
3245
// Guarded through GetInstance() already.
3346
instance_id_by_app_[app] = this;
3447

@@ -132,6 +145,98 @@ Future<void> InstanceIdDesktopImpl::DeleteTokenLastResult() {
132145
ref_future()->LastResult(kInstanceIdFnRemoveToken));
133146
}
134147

148+
// Save the instance ID to local secure storage.
149+
bool InstanceIdDesktopImpl::SaveToStorage() {
150+
// Build up a serialized buffer algorithmically:
151+
flatbuffers::FlatBufferBuilder builder;
152+
153+
auto iid_data_table = CreateInstanceIdDesktopDataDirect(
154+
builder, instance_id_.c_str(), checkin_data_.device_id.c_str(),
155+
checkin_data_.security_token.c_str(), expiration_time_);
156+
builder.Finish(iid_data_table);
157+
158+
std::string save_string;
159+
auto bufferpointer =
160+
reinterpret_cast<const char*>(builder.GetBufferPointer());
161+
save_string.assign(bufferpointer, bufferpointer + builder.GetSize());
162+
// Encode flatbuffer
163+
std::string encoded;
164+
UserSecureManager::BinaryToAscii(save_string, &encoded);
165+
166+
Future<void> future =
167+
user_secure_manager_->SaveUserData(app_->name(), encoded);
168+
169+
future.OnCompletion(
170+
[](const Future<void>& result, void* sem_void) {
171+
Semaphore* sem_ptr = reinterpret_cast<Semaphore*>(sem_void);
172+
sem_ptr->Post();
173+
},
174+
&storage_semaphore_);
175+
storage_semaphore_.Wait();
176+
return future.error() == 0;
177+
}
178+
179+
// Load the instance ID from local secure storage.
180+
bool InstanceIdDesktopImpl::LoadFromStorage() {
181+
Future<std::string> future = user_secure_manager_->LoadUserData(app_->name());
182+
183+
future.OnCompletion(
184+
[](const Future<std::string>& result, void* sem_void) {
185+
Semaphore* sem_ptr = reinterpret_cast<Semaphore*>(sem_void);
186+
sem_ptr->Post();
187+
},
188+
&storage_semaphore_);
189+
storage_semaphore_.Wait();
190+
if (future.error() == 0) {
191+
ReadStoredInstanceIdData(*future.result());
192+
}
193+
return future.error() == 0;
194+
}
195+
196+
// Delete the instance ID from local secure storage.
197+
bool InstanceIdDesktopImpl::DeleteFromStorage() {
198+
Future<void> future = user_secure_manager_->DeleteUserData(app_->name());
199+
200+
future.OnCompletion(
201+
[](const Future<void>& result, void* sem_void) {
202+
Semaphore* sem_ptr = reinterpret_cast<Semaphore*>(sem_void);
203+
sem_ptr->Post();
204+
},
205+
&storage_semaphore_);
206+
storage_semaphore_.Wait();
207+
return future.error() == 0;
208+
}
209+
210+
// Returns true if data was successfully read.
211+
bool InstanceIdDesktopImpl::ReadStoredInstanceIdData(
212+
const std::string& loaded_string) {
213+
// Decode to flatbuffer
214+
std::string decoded;
215+
if (!UserSecureManager::AsciiToBinary(loaded_string, &decoded)) {
216+
LogWarning("Error decoding saved Instance ID.");
217+
return false;
218+
}
219+
// Verify the Flatbuffer is valid.
220+
flatbuffers::Verifier verifier(
221+
reinterpret_cast<const uint8_t*>(decoded.c_str()), decoded.length());
222+
if (!VerifyInstanceIdDesktopDataBuffer(verifier)) {
223+
LogWarning("Error verifying saved Instance ID.");
224+
return false;
225+
}
226+
227+
auto iid_data_fb = GetInstanceIdDesktopData(decoded.c_str());
228+
if (iid_data_fb == nullptr) {
229+
LogWarning("Error reading table for saved Instance ID.");
230+
return false;
231+
}
232+
233+
instance_id_ = iid_data_fb->instance_id()->c_str();
234+
checkin_data_.device_id = iid_data_fb->device_id()->c_str();
235+
checkin_data_.security_token = iid_data_fb->security_token()->c_str();
236+
expiration_time_ = iid_data_fb->expiration_time();
237+
return true;
238+
}
239+
135240
} // namespace internal
136241
} // namespace instance_id
137242
} // namespace firebase

app/instance_id/instance_id_desktop_impl.h

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,23 @@
1515
#ifndef FIREBASE_APP_CLIENT_CPP_INSTANCE_ID_INSTANCE_ID_DESKTOP_IMPL_H_
1616
#define FIREBASE_APP_CLIENT_CPP_INSTANCE_ID_INSTANCE_ID_DESKTOP_IMPL_H_
1717

18+
#include <cstdint>
1819
#include <map>
1920
#include <string>
2021

22+
#include "app/memory/unique_ptr.h"
2123
#include "app/src/future_manager.h"
2224
#include "app/src/include/firebase/app.h"
2325
#include "app/src/include/firebase/future.h"
24-
#include "app/src/mutex.h"
26+
#include "app/src/secure/user_secure_manager.h"
27+
#include "app/src/semaphore.h"
2528

2629
namespace firebase {
2730
namespace instance_id {
2831
namespace internal {
2932

33+
class InstanceIdDesktopImplTest; // For testing.
34+
3035
class InstanceIdDesktopImpl {
3136
public:
3237
// Future functions for Instance Id
@@ -35,6 +40,9 @@ class InstanceIdDesktopImpl {
3540
kInstanceIdFnRemoveId,
3641
kInstanceIdFnGetToken,
3742
kInstanceIdFnRemoveToken,
43+
kInstanceIdFnStorageSave,
44+
kInstanceIdFnStorageLoad,
45+
kInstanceIdFnStorageDelete,
3846
kInstanceIdFnCount,
3947
};
4048

@@ -90,6 +98,8 @@ class InstanceIdDesktopImpl {
9098
App& app() { return *app_; }
9199

92100
private:
101+
friend class InstanceIdDesktopImplTest;
102+
93103
explicit InstanceIdDesktopImpl(App* app);
94104

95105
// Get future manager of this object
@@ -100,12 +110,43 @@ class InstanceIdDesktopImpl {
100110
return future_manager().GetFutureApi(this);
101111
}
102112

113+
// Verify and parse the stored IID data, called by LoadFromStorage(), and fill
114+
// in this class. Returns false if there are any parsing errors.
115+
bool ReadStoredInstanceIdData(const std::string& loaded_string);
116+
117+
// For testing only, to use a fake UserSecureManager.
118+
void SetUserSecureManager(
119+
UniquePtr<firebase::app::secure::UserSecureManager> manager) {
120+
user_secure_manager_ = manager;
121+
}
122+
123+
// Save the instance ID to local secure storage. Blocking.
124+
bool SaveToStorage();
125+
// Load the instance ID from local secure storage. Blocking.
126+
bool LoadFromStorage();
127+
// Delete the instance ID from local secure storage. Blocking.
128+
bool DeleteFromStorage();
129+
130+
// Used to wait for async storage functions to finish.
131+
Semaphore storage_semaphore_;
132+
133+
struct CheckinData {
134+
std::string security_token;
135+
std::string device_id;
136+
};
137+
103138
// Future manager of this object
104139
FutureManager future_manager_;
105140

106141
// The App this object is connected to.
107142
App* app_;
108143

144+
UniquePtr<firebase::app::secure::UserSecureManager> user_secure_manager_;
145+
146+
CheckinData checkin_data_;
147+
std::string instance_id_;
148+
uint64_t expiration_time_;
149+
109150
// Global map of App to InstanceIdDesktopImpl
110151
static std::map<App*, InstanceIdDesktopImpl*> instance_id_by_app_;
111152

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright 2019 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "app/src/secure/user_secure_manager_fake.h"
16+
17+
#include "app/memory/unique_ptr.h"
18+
#include "app/src/secure/user_secure_fake_internal.h"
19+
20+
namespace firebase {
21+
namespace app {
22+
namespace secure {
23+
24+
#if defined(_WIN32)
25+
static const char kDirectorySeparator[] = "\\";
26+
#else
27+
static const char kDirectorySeparator[] = "/";
28+
#endif // defined(_WIN32)
29+
30+
// Get temp directory for fake secure storage.
31+
static std::string GetTestTmpDir(const char test_namespace[]) {
32+
#if defined(_WIN32)
33+
char buf[MAX_PATH + 1];
34+
if (GetEnvironmentVariable("TEST_TMPDIR", buf, sizeof(buf))) {
35+
return std::string(buf) + kDirectorySeparator + test_namespace;
36+
}
37+
#else
38+
// Linux and OS X should either have the TEST_TMPDIR environment variable set.
39+
if (const char* value = getenv("TEST_TMPDIR")) {
40+
return std::string(value) + kDirectorySeparator + test_namespace;
41+
}
42+
#endif // defined(_WIN32)
43+
// If we weren't able to get TEST_TMPDIR, just use a subdirectory.
44+
return test_namespace;
45+
}
46+
47+
UserSecureManagerFake::UserSecureManagerFake(const char* domain,
48+
const char* app_id)
49+
: UserSecureManager(MakeUnique<UserSecureFakeInternal>(
50+
domain, GetTestTmpDir(app_id).c_str())) {}
51+
52+
} // namespace secure
53+
} // namespace app
54+
} // namespace firebase
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
2+
// Copyright 2019 Google LLC
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
#ifndef FIREBASE_APP_CLIENT_CPP_SRC_SECURE_USER_SECURE_MANAGER_FAKE_H_
17+
#define FIREBASE_APP_CLIENT_CPP_SRC_SECURE_USER_SECURE_MANAGER_FAKE_H_
18+
19+
#include "app/src/secure/user_secure_manager.h"
20+
21+
namespace firebase {
22+
namespace app {
23+
namespace secure {
24+
25+
// Fake version of UserSecureManager usable for testing. Stores to TEST_TMPDIR.
26+
class UserSecureManagerFake : public UserSecureManager {
27+
public:
28+
explicit UserSecureManagerFake(const char* domain, const char* app_id);
29+
};
30+
31+
} // namespace secure
32+
} // namespace app
33+
} // namespace firebase
34+
35+
#endif // FIREBASE_APP_CLIENT_CPP_SRC_SECURE_USER_SECURE_MANAGER_FAKE_H_

0 commit comments

Comments
 (0)