Skip to content

Commit 33665b2

Browse files
authored
Restrict Firebase API key to Android app package name. (#690)
* Implement Firebase segmentation SDK device local cache * [Firebase Segmentation] Add custom installation id cache layer and tests for it. * Add test for updating cache * Switch to use SQLiteOpenHelper * Switch to use SharedPreferences from SQLite. * Change the cache class to be singleton * Wrap shared pref commit in a async task. * Address comments * Google format fix * Replace some deprecated code. * Package refactor * nit * nit * Add the state machine of updating custom installation id in the local cache and update to Firebase Segmentation backend. CL also contains unit tests. (The http client is not implemented yet.) * minor format fix * Address comments #1 * Http client in Firebase Segmentation SDK to call backend service. * Revert unintentional change * Fix connected device test * Fix connected device test * 1. Add a few annotations to make java code Kotlin friendly 2. Some fixes for the http request format * Fix java format * Fix API version * Change the segmentation API implementation to synchronous and put the entire synchronous code block in async task. * Fix a async getResult race issue. * OkHttpClient -> HttpsUrlConnection * Use gzip for compressing content and fix ourput stream memory leak risk. * Addressed a few comments * FirebaseSegmentation SDK 1. Clean up http client response code. 2. When updateCustomInstallationId is called, on non-retryable server errors, the SDK should clean up the local cache. Instead, for retryable errors, SDK can keep the local cache for retrying update later. * Restrict Firebase API key to Android app package name.
1 parent 52d259d commit 33665b2

File tree

2 files changed

+44
-1
lines changed

2 files changed

+44
-1
lines changed

firebase-segmentation/src/main/java/com/google/firebase/segmentation/FirebaseSegmentation.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
/** Entry point of Firebase Segmentation SDK. */
3636
public class FirebaseSegmentation {
3737

38+
public static final String TAG = "FirebaseSegmentation";
39+
3840
private final FirebaseApp firebaseApp;
3941
private final FirebaseInstanceId firebaseInstanceId;
4042
private final CustomInstallationIdCache localCache;
@@ -46,7 +48,7 @@ public class FirebaseSegmentation {
4648
firebaseApp,
4749
FirebaseInstanceId.getInstance(firebaseApp),
4850
new CustomInstallationIdCache(firebaseApp),
49-
new SegmentationServiceClient());
51+
new SegmentationServiceClient(firebaseApp.getApplicationContext()));
5052
}
5153

5254
FirebaseSegmentation(

firebase-segmentation/src/main/java/com/google/firebase/segmentation/remote/SegmentationServiceClient.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,14 @@
1414

1515
package com.google.firebase.segmentation.remote;
1616

17+
import static com.google.firebase.segmentation.FirebaseSegmentation.TAG;
18+
19+
import android.content.Context;
20+
import android.content.pm.PackageManager;
21+
import android.util.Log;
1722
import androidx.annotation.NonNull;
23+
import com.google.android.gms.common.util.AndroidUtilsLight;
24+
import com.google.android.gms.common.util.Hex;
1825
import java.io.IOException;
1926
import java.net.URL;
2027
import java.util.zip.GZIPOutputStream;
@@ -37,6 +44,14 @@ public class SegmentationServiceClient {
3744
private static final String JSON_CONTENT_TYPE = "application/json";
3845
private static final String CONTENT_ENCODING_HEADER_KEY = "Content-Encoding";
3946
private static final String GZIP_CONTENT_ENCODING = "gzip";
47+
private static final String X_ANDROID_PACKAGE_HEADER_KEY = "X-Android-Package";
48+
private static final String X_ANDROID_CERT_HEADER_KEY = "X-Android-Cert";
49+
50+
private final Context context;
51+
52+
public SegmentationServiceClient(@NonNull Context context) {
53+
this.context = context;
54+
}
4055

4156
public enum Code {
4257
OK,
@@ -78,6 +93,9 @@ public Code updateCustomInstallationId(
7893
"Authorization", "FIREBASE_INSTALLATIONS_AUTH " + firebaseInstanceIdToken);
7994
httpsURLConnection.addRequestProperty(CONTENT_TYPE_HEADER_KEY, JSON_CONTENT_TYPE);
8095
httpsURLConnection.addRequestProperty(CONTENT_ENCODING_HEADER_KEY, GZIP_CONTENT_ENCODING);
96+
httpsURLConnection.addRequestProperty(X_ANDROID_PACKAGE_HEADER_KEY, context.getPackageName());
97+
httpsURLConnection.addRequestProperty(
98+
X_ANDROID_CERT_HEADER_KEY, getFingerprintHashForPackage());
8199
GZIPOutputStream gzipOutputStream =
82100
new GZIPOutputStream(httpsURLConnection.getOutputStream());
83101
try {
@@ -143,6 +161,9 @@ public Code clearCustomInstallationId(
143161
"Authorization", "FIREBASE_INSTALLATIONS_AUTH " + firebaseInstanceIdToken);
144162
httpsURLConnection.addRequestProperty(CONTENT_TYPE_HEADER_KEY, JSON_CONTENT_TYPE);
145163
httpsURLConnection.addRequestProperty(CONTENT_ENCODING_HEADER_KEY, GZIP_CONTENT_ENCODING);
164+
httpsURLConnection.addRequestProperty(X_ANDROID_PACKAGE_HEADER_KEY, context.getPackageName());
165+
httpsURLConnection.addRequestProperty(
166+
X_ANDROID_CERT_HEADER_KEY, getFingerprintHashForPackage());
146167
GZIPOutputStream gzipOutputStream =
147168
new GZIPOutputStream(httpsURLConnection.getOutputStream());
148169
try {
@@ -175,4 +196,24 @@ private static JSONObject buildClearCustomSegmentationDataRequestBody(String res
175196
throws JSONException {
176197
return new JSONObject().put("name", resourceName);
177198
}
199+
200+
/** Gets the Android package's SHA-1 fingerprint. */
201+
private String getFingerprintHashForPackage() {
202+
byte[] hash;
203+
204+
try {
205+
hash = AndroidUtilsLight.getPackageCertificateHashBytes(context, context.getPackageName());
206+
207+
if (hash == null) {
208+
Log.e(TAG, "Could not get fingerprint hash for package: " + context.getPackageName());
209+
return null;
210+
} else {
211+
String cert = Hex.bytesToStringUppercase(hash, /* zeroTerminated= */ false);
212+
return Hex.bytesToStringUppercase(hash, /* zeroTerminated= */ false);
213+
}
214+
} catch (PackageManager.NameNotFoundException e) {
215+
Log.e(TAG, "No such package: " + context.getPackageName(), e);
216+
return null;
217+
}
218+
}
178219
}

0 commit comments

Comments
 (0)