Skip to content

Commit 2d581bd

Browse files
jonsimantova-maurice
authored andcommitted
Implement Firebase Instance ID on desktop to call into App's IID library.
Implement GetId() and GetToken() synchronously (for now). DeleteId() and DeleteToken() are also implemented synchronously (though they don't call Delete on the server yet). Turns out that the AppId needs to use an alternate version of Base64 that is "url safe" so this CL adds support for that as well, and fleshes out the tests/fuzzer to ensure coverage. PiperOrigin-RevId: 248639274
1 parent ffa0432 commit 2d581bd

File tree

10 files changed

+344
-34
lines changed

10 files changed

+344
-34
lines changed

app/instance_id/instance_id_desktop_impl.cc

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,18 @@ InstanceIdDesktopImpl* InstanceIdDesktopImpl::GetInstance(App* app) {
135135
}
136136

137137
Future<std::string> InstanceIdDesktopImpl::GetId() {
138-
// TODO(b/132622932)
138+
// GetId() -> Check-in, generate an ID / get cached ID, return the ID
139139
SafeFutureHandle<std::string> handle =
140140
ref_future()->SafeAlloc<std::string>(kInstanceIdFnGetId);
141-
ref_future()->Complete(handle, kErrorUnavailable, "Not Implemented yet");
142141

143-
return MakeFuture(ref_future(), handle);
142+
Future<std::string> future = MakeFuture(ref_future(), handle);
143+
if (!InitialOrRefreshCheckin()) {
144+
ref_future()->Complete(handle, kErrorUnavailable, "Error in checkin");
145+
return future;
146+
}
147+
ref_future()->CompleteWithResult(handle, 0, "", instance_id_);
148+
149+
return future;
144150
}
145151

146152
Future<std::string> InstanceIdDesktopImpl::GetIdLastResult() {
@@ -149,10 +155,25 @@ Future<std::string> InstanceIdDesktopImpl::GetIdLastResult() {
149155
}
150156

151157
Future<void> InstanceIdDesktopImpl::DeleteId() {
152-
// TODO(b/132621850)
158+
// DeleteId() -> Delete all tokens and remove them from the cache, then clear
159+
// ID.
153160
SafeFutureHandle<void> handle =
154161
ref_future()->SafeAlloc<void>(kInstanceIdFnRemoveId);
155-
ref_future()->Complete(handle, kErrorUnavailable, "Not Implemented yet");
162+
163+
std::vector<std::string> token_scopes;
164+
for (auto i = tokens_.begin(); i != tokens_.end(); ++i) {
165+
token_scopes.push_back(i->first);
166+
}
167+
// Delete all tokens.
168+
while (!token_scopes.empty()) {
169+
/* TODO DeleteTokenRequest(token_scopes.back()); */
170+
DeleteCachedToken(token_scopes.back().c_str());
171+
token_scopes.pop_back();
172+
}
173+
instance_id_ = "";
174+
DeleteFromStorage();
175+
checkin_data_.Clear();
176+
ref_future()->Complete(handle, 0, "");
156177

157178
return MakeFuture(ref_future(), handle);
158179
}
@@ -162,11 +183,20 @@ Future<void> InstanceIdDesktopImpl::DeleteIdLastResult() {
162183
ref_future()->LastResult(kInstanceIdFnRemoveId));
163184
}
164185

165-
Future<std::string> InstanceIdDesktopImpl::GetToken() {
166-
// TODO(b/132622932)
186+
Future<std::string> InstanceIdDesktopImpl::GetToken(const char* scope) {
187+
// GetToken() -> GetId() then get token from cache or using check-in
188+
// information, return the token
189+
167190
SafeFutureHandle<std::string> handle =
168191
ref_future()->SafeAlloc<std::string>(kInstanceIdFnGetToken);
169-
ref_future()->Complete(handle, kErrorUnavailable, "Not Implemented yet");
192+
193+
std::string scope_str(scope);
194+
if (FetchToken(scope_str.c_str())) {
195+
ref_future()->CompleteWithResult(handle, 0, "",
196+
FindCachedToken(scope_str.c_str()));
197+
} else {
198+
ref_future()->Complete(handle, kErrorUnknownError, "FetchToken failed");
199+
}
170200

171201
return MakeFuture(ref_future(), handle);
172202
}
@@ -176,12 +206,20 @@ Future<std::string> InstanceIdDesktopImpl::GetTokenLastResult() {
176206
ref_future()->LastResult(kInstanceIdFnGetToken));
177207
}
178208

179-
Future<void> InstanceIdDesktopImpl::DeleteToken() {
180-
// TODO(b/132621850)
209+
Future<void> InstanceIdDesktopImpl::DeleteToken(const char* scope) {
210+
// DeleteToken() --> delete token request and remove from the cache
211+
181212
SafeFutureHandle<void> handle =
182213
ref_future()->SafeAlloc<void>(kInstanceIdFnRemoveToken);
183-
ref_future()->Complete(handle, kErrorUnavailable, "Not Implemented yet");
184214

215+
std::string scope_str(scope);
216+
DeleteCachedToken(scope_str.c_str());
217+
if (/*ServerDeleteToken(scope_str.c_str() && */
218+
tokens_.find(scope_str) == tokens_.end()) {
219+
ref_future()->Complete(handle, 0, "");
220+
} else {
221+
ref_future()->Complete(handle, kErrorUnknownError, "DeleteToken failed");
222+
}
185223
return MakeFuture(ref_future(), handle);
186224
}
187225

@@ -315,11 +353,14 @@ bool InstanceIdDesktopImpl::InitialOrRefreshCheckin() {
315353
instance_id_ = GenerateAppId();
316354
}
317355

356+
if (checkin_data_.device_id.empty() || checkin_data_.security_token.empty() ||
357+
checkin_data_.digest.empty()) {
358+
// If any of these aren't set, checkin data is incomplete, so clear it.
359+
checkin_data_.Clear();
360+
}
361+
318362
// If we've already checked in.
319363
if (checkin_data_.last_checkin_time_ms > 0) {
320-
FIREBASE_ASSERT(!checkin_data_.device_id.empty() &&
321-
!checkin_data_.security_token.empty() &&
322-
!checkin_data_.digest.empty());
323364
// Make sure the device ID and token aren't expired.
324365
uint64_t time_elapsed_ms =
325366
firebase::internal::GetTimestamp() - checkin_data_.last_checkin_time_ms;
@@ -465,7 +506,7 @@ std::string InstanceIdDesktopImpl::GenerateAppId() {
465506
std::string input(reinterpret_cast<char*>(buffer), sizeof(buffer));
466507
std::string output;
467508

468-
if (firebase::internal::Base64Encode(input, &output)) {
509+
if (firebase::internal::Base64EncodeUrlSafe(input, &output)) {
469510
return output;
470511
}
471512
return ""; // Error encoding.

app/instance_id/instance_id_desktop_impl.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,13 @@ class InstanceIdDesktopImpl {
8787

8888
// Returns a token that authorizes an Entity to perform an action on
8989
// behalf of the application identified by Instance ID.
90-
Future<std::string> GetToken();
90+
Future<std::string> GetToken(const char* scope);
9191

9292
// Get the results of the most recent call to @ref GetToken.
9393
Future<std::string> GetTokenLastResult();
9494

9595
// Revokes access to a scope (action)
96-
Future<void> DeleteToken();
96+
Future<void> DeleteToken(const char* scope);
9797

9898
// Get the results of the most recent call to @ref DeleteToken.
9999
Future<void> DeleteTokenLastResult();

app/src/base64.cc

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,19 @@ namespace internal {
2727
// Maps 6-bit index to base64 encoded character.
2828
static const char kBase64Table[] =
2929
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
30+
static const char kBase64TableUrlSafe[] =
31+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
3032

3133
// Reverse lookup for kBase64Table above; -1 signifies an invalid character.
3234
// Maps ASCII value to 6-bit index.
3335
// clang-format off
3436
static const int8_t kBase64TableReverse[256] = {
3537
/* 0 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
3638
/* 16 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
37-
/* 32 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
39+
/* 32 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63,
3840
/* 48 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1,
3941
/* 64 */ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
40-
/* 80 */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
42+
/* 80 */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
4143
/* 96 */ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
4244
/* 112 */ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
4345
/* 128 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
@@ -58,7 +60,7 @@ static const char kBase64NullEnding = '=';
5860

5961
// Base64 encode a string (binary allowed). Returns true if successful.
6062
static bool Base64EncodeInternal(const std::string& input, std::string* output,
61-
bool pad_to_32_bits) {
63+
bool url_safe, bool pad_to_32_bits) {
6264
if (!output) {
6365
return false;
6466
}
@@ -68,6 +70,8 @@ static bool Base64EncodeInternal(const std::string& input, std::string* output,
6870
std::string inplace_buffer;
6971
std::string* output_ptr = inplace ? &inplace_buffer : output;
7072

73+
const char* base64_table = url_safe ? kBase64TableUrlSafe : kBase64Table;
74+
7175
// The base64 algorithm is pretty simple: take 3 bytes = 24 bits of data at a
7276
// time, and encode them in four 6-bit chunks.
7377
output_ptr->resize(GetBase64EncodedSize(input));
@@ -80,13 +84,13 @@ static bool Base64EncodeInternal(const std::string& input, std::string* output,
8084

8185
uint32_t stream = (b2 & 0xFF) | ((b1 & 0xFF) << 8) | ((b0 & 0xFF) << 16);
8286

83-
(*output_ptr)[o + 0] = kBase64Table[(stream >> 18) & 0x3F];
84-
(*output_ptr)[o + 1] = kBase64Table[(stream >> 12) & 0x3F];
87+
(*output_ptr)[o + 0] = base64_table[(stream >> 18) & 0x3F];
88+
(*output_ptr)[o + 1] = base64_table[(stream >> 12) & 0x3F];
8589
(*output_ptr)[o + 2] = (i + 1 < input.size())
86-
? kBase64Table[(stream >> 6) & 0x3F]
90+
? base64_table[(stream >> 6) & 0x3F]
8791
: kBase64NullEnding;
8892
(*output_ptr)[o + 3] = (i + 2 < input.size())
89-
? kBase64Table[(stream >> 0) & 0x3F]
93+
? base64_table[(stream >> 0) & 0x3F]
9094
: kBase64NullEnding;
9195
}
9296
if (!pad_to_32_bits) {
@@ -108,11 +112,20 @@ static bool Base64EncodeInternal(const std::string& input, std::string* output,
108112
}
109113

110114
bool Base64Encode(const std::string& input, std::string* output) {
111-
return Base64EncodeInternal(input, output, false);
115+
return Base64EncodeInternal(input, output, false, false);
112116
}
113117

114118
bool Base64EncodeWithPadding(const std::string& input, std::string* output) {
115-
return Base64EncodeInternal(input, output, true);
119+
return Base64EncodeInternal(input, output, false, true);
120+
}
121+
122+
bool Base64EncodeUrlSafe(const std::string& input, std::string* output) {
123+
return Base64EncodeInternal(input, output, true, false);
124+
}
125+
126+
bool Base64EncodeUrlSafeWithPadding(const std::string& input,
127+
std::string* output) {
128+
return Base64EncodeInternal(input, output, true, true);
116129
}
117130

118131
// Get the size that a given string would take up if encoded to Base64.

app/src/base64.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,23 @@ bool Base64Encode(const std::string& input, std::string* output);
2929
// Pads output to 32 bits by adding = or == to the end, as is tradition.
3030
bool Base64EncodeWithPadding(const std::string& input, std::string* output);
3131

32+
// Base64 encode a string (binary allowed). Returns true if successful.
33+
// Uses URL-safe characters (- and _ in place of + and /).
34+
bool Base64EncodeUrlSafe(const std::string& input, std::string* output);
35+
36+
// Base64 encode a string (binary allowed). Returns true if successful.
37+
// Pads output to 32 bits by adding = or == to the end, as is tradition.
38+
// Uses URL-safe characters (- and _ in place of + and /).
39+
bool Base64EncodeUrlSafeWithPadding(const std::string& input,
40+
std::string* output);
41+
3242
// Get the size that a given string would take up if encoded to Base64, rounded
3343
// up to the next 4 bytes.
3444
size_t GetBase64EncodedSize(const std::string& input);
3545

3646
// Base64 decode a string (may output binary). Returns true if successful, or
3747
// false if there is an error (in which case the output string is undefined).
38-
bool Base64Decode(const std::string& input, std::string* output);
39-
40-
// Base64 decode a string (may output binary). Returns true if successful, or
41-
// false if there is an error (in which case the output string is undefined).
48+
// Can parse standard or url-safe characters.
4249
bool Base64Decode(const std::string& input, std::string* output);
4350

4451
// Get the size that a given string would take up if decoded from Base64.

app/src/base64_fuzzer.cc

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,27 @@
2020
#include "app/src/base64.h"
2121

2222
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
23-
// Test encoding and decoding this string.
23+
// Test encoding and decoding this string with various permutations of
24+
// options.
2425
std::string orig(reinterpret_cast<const char *>(data), size);
2526
std::string encoded, decoded;
26-
bool success = firebase::internal::Base64Encode(orig, &encoded);
27+
bool success;
28+
success = firebase::internal::Base64Encode(orig, &encoded);
29+
assert(success);
30+
success = firebase::internal::Base64Decode(encoded, &decoded);
31+
assert(success);
32+
assert(orig == decoded);
33+
success = firebase::internal::Base64EncodeWithPadding(orig, &encoded);
34+
assert(success);
35+
success = firebase::internal::Base64Decode(encoded, &decoded);
36+
assert(success);
37+
assert(orig == decoded);
38+
success = firebase::internal::Base64EncodeUrlSafe(orig, &encoded);
39+
assert(success);
40+
success = firebase::internal::Base64Decode(encoded, &decoded);
41+
assert(success);
42+
assert(orig == decoded);
43+
success = firebase::internal::Base64EncodeUrlSafeWithPadding(orig, &encoded);
2744
assert(success);
2845
success = firebase::internal::Base64Decode(encoded, &decoded);
2946
assert(success);

0 commit comments

Comments
 (0)