From cbbffa5bb568008275d5c23b1194e746ff73c8a2 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Mon, 13 Apr 2020 17:43:59 -0700 Subject: [PATCH 1/3] Add precondition format checks for AppId and API Key --- .../installations/FirebaseInstallations.java | 8 ++++ .../google/firebase/installations/Utils.java | 12 ++++++ .../FirebaseInstallationsTest.java | 40 ++++++++++++++++++- 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/firebase-installations/src/main/java/com/google/firebase/installations/FirebaseInstallations.java b/firebase-installations/src/main/java/com/google/firebase/installations/FirebaseInstallations.java index 4c1191b57b8..a0e68a92199 100644 --- a/firebase-installations/src/main/java/com/google/firebase/installations/FirebaseInstallations.java +++ b/firebase-installations/src/main/java/com/google/firebase/installations/FirebaseInstallations.java @@ -146,6 +146,14 @@ private void preConditionChecks() { Preconditions.checkNotEmpty(getApplicationId()); Preconditions.checkNotEmpty(getProjectIdentifier()); Preconditions.checkNotEmpty(getApiKey()); + Preconditions.checkArgument( + Utils.isValidAppIdFormat(getApplicationId()), + "Invalid AppId format. Please refer to" + + " https://firebase.google.com/support/privacy/init-options for details."); + Preconditions.checkArgument( + Utils.isValidApiKeyFormat(getApiKey()), + "Invalid Api-key format. Please refer to" + + " https://firebase.google.com/support/privacy/init-options for details."); } /** Returns the Project Id or Project Number for the Firebase Project. */ diff --git a/firebase-installations/src/main/java/com/google/firebase/installations/Utils.java b/firebase-installations/src/main/java/com/google/firebase/installations/Utils.java index fb8b0deeb19..4b4a592b024 100644 --- a/firebase-installations/src/main/java/com/google/firebase/installations/Utils.java +++ b/firebase-installations/src/main/java/com/google/firebase/installations/Utils.java @@ -17,11 +17,15 @@ import android.text.TextUtils; import com.google.firebase.installations.local.PersistedInstallationEntry; import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; /** Util methods used for {@link FirebaseInstallations} */ class Utils { public static final long AUTH_TOKEN_EXPIRATION_BUFFER_IN_SECS = TimeUnit.HOURS.toSeconds(1); + private static final String APP_ID_IDENTIFICATION_SUBSTRING = ":"; + private static final Pattern API_KEY_FORMAT = Pattern.compile("\\AA[\\w-]{38}\\z"); + /** * Checks if the FIS Auth token is expired or going to expire in next 1 hour {@link * #AUTH_TOKEN_EXPIRATION_BUFFER_IN_SECS}. @@ -41,4 +45,12 @@ public boolean isAuthTokenExpired(PersistedInstallationEntry entry) { public long currentTimeInSecs() { return TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()); } + + static boolean isValidAppIdFormat(String AppId) { + return AppId.contains(APP_ID_IDENTIFICATION_SUBSTRING); + } + + static boolean isValidApiKeyFormat(String ApiKey) { + return API_KEY_FORMAT.matcher(ApiKey).matches(); + } } diff --git a/firebase-installations/src/test/java/com/google/firebase/installations/FirebaseInstallationsTest.java b/firebase-installations/src/test/java/com/google/firebase/installations/FirebaseInstallationsTest.java index afd26f91b0b..1eb3d0e9417 100644 --- a/firebase-installations/src/test/java/com/google/firebase/installations/FirebaseInstallationsTest.java +++ b/firebase-installations/src/test/java/com/google/firebase/installations/FirebaseInstallationsTest.java @@ -17,6 +17,7 @@ import static com.google.common.truth.Truth.assertWithMessage; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; @@ -82,7 +83,7 @@ public class FirebaseInstallationsTest { public static final String TEST_AUTH_TOKEN_3 = "fis.auth.token3"; public static final String TEST_AUTH_TOKEN_4 = "fis.auth.token4"; - public static final String TEST_API_KEY = "apiKey"; + public static final String TEST_API_KEY = "AIzaSyabcdefghijklmnopqrstuvwxyz1234567"; public static final String TEST_REFRESH_TOKEN = "1:test-refresh-token"; @@ -965,4 +966,41 @@ public void testDelete_networkError() throws Exception { entry.isRegistered()); } } + + @Test + public void testAppIdCheck() { + // valid appid + assertTrue(Utils.isValidAppIdFormat("1:123456789:android:abcdef")); + assertTrue(Utils.isValidAppIdFormat("1:515438998704:android:e78ec19738058349")); + assertTrue(Utils.isValidAppIdFormat("1:208472424340:android:a243f98a00873753")); + assertTrue(Utils.isValidAppIdFormat("1:755541669657:ios:4d6d5a5ce71e9d30")); + assertTrue(Utils.isValidAppIdFormat("1:1086610230652:ios:852c7f6ee799ff89")); + assertTrue(Utils.isValidAppIdFormat("1:35006771263:web:32b6f4a5b95acd2c")); + // invalid appid + assertFalse(Utils.isValidAppIdFormat("abc.abc.abc")); + assertFalse( + Utils.isValidAppIdFormat( + "com.google.firebase.samples.messaging.advanced")); // using pakage name as App ID + } + + @Test + public void testApiKeyCheck() { + // valid ApiKey + assertTrue(Utils.isValidApiKeyFormat("AIzaSyabcdefghijklmnopqrstuvwxyz1234567")); + assertTrue(Utils.isValidApiKeyFormat("AIzaSyA4UrcGxgwQFTfaI3no3t7Lt1sjmdnP5sQ")); + assertTrue(Utils.isValidApiKeyFormat("AIzaSyA5_iVawFQ8ABuTZNUdcwERLJv_a_p4wtM")); + assertTrue(Utils.isValidApiKeyFormat("AIzaSyANUvH9H9BsUccjsu2pCmEkOPjjaXeDQgY")); + assertTrue(Utils.isValidApiKeyFormat("AIzaSyASWm6HmTMdYWpgMnjRBjxcQ9CKctWmLd4")); + assertTrue(Utils.isValidApiKeyFormat("AIzaSyAdOS2zB6NCsk1pCdZ4-P6GBdi_UUPwX7c")); + assertTrue(Utils.isValidApiKeyFormat("AIzaSyAnLA7NfeLquW1tJFpx_eQCxoX-oo6YyIs")); + // invalid ApiKey + assertFalse( + Utils.isValidApiKeyFormat("BIzaSyabcdefghijklmnopqrstuvwxyz1234567")); // wrong prefix + assertFalse(Utils.isValidApiKeyFormat("AIzaSyabcdefghijklmnopqrstuvwxyz")); // wrong length + assertFalse(Utils.isValidApiKeyFormat("AIzaSyabcdefghijklmno:qrstuvwxyzabcdefg")); // wrong char + assertFalse(Utils.isValidApiKeyFormat("AIzaSyabcdefghijklmno qrstuvwxyzabcdefg")); // wrong char + assertFalse( + Utils.isValidApiKeyFormat( + "AAAAdpB7anM:APA91bFFK03DIT8y3l5uymwbKcUDJdYqTRSP9Qcxg8SU5kKPalEpObdx0C0xv8gQttdWlLW4hLvvHA0JoDKA6Lrvbi-edUjFCPY_WJkuvHxFwGWXjnj4yI4sPQ27mXuSVIyAbgX4aTK0QYpIKq2j1NBi7ZU75gunQg")); // using FCM server key as API key. + } } From 137c97d28a6e02684e3b1c847eae0d824b3a2743 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Tue, 14 Apr 2020 00:11:07 -0700 Subject: [PATCH 2/3] fix minor issue --- .../firebase/installations/FirebaseInstallations.java | 10 ++++++---- .../java/com/google/firebase/installations/Utils.java | 11 +++++++---- .../installations/FirebaseInstallationsTest.java | 4 +++- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/firebase-installations/src/main/java/com/google/firebase/installations/FirebaseInstallations.java b/firebase-installations/src/main/java/com/google/firebase/installations/FirebaseInstallations.java index a0e68a92199..7aaa5518cd1 100644 --- a/firebase-installations/src/main/java/com/google/firebase/installations/FirebaseInstallations.java +++ b/firebase-installations/src/main/java/com/google/firebase/installations/FirebaseInstallations.java @@ -148,12 +148,14 @@ private void preConditionChecks() { Preconditions.checkNotEmpty(getApiKey()); Preconditions.checkArgument( Utils.isValidAppIdFormat(getApplicationId()), - "Invalid AppId format. Please refer to" - + " https://firebase.google.com/support/privacy/init-options for details."); + "Please set your Application ID. A valid Firebase App ID is required to communicate " + + "with Firebase server APIs: It identifies your application with Firebase." + + "Please refer to https://firebase.google.com/support/privacy/init-options."); Preconditions.checkArgument( Utils.isValidApiKeyFormat(getApiKey()), - "Invalid Api-key format. Please refer to" - + " https://firebase.google.com/support/privacy/init-options for details."); + "Please set a valid API key. A Firebase API key is required to communicate with " + + "Firebase server APIs: It authenticates your project with Google." + + "Please refer to https://firebase.google.com/support/privacy/init-options."); } /** Returns the Project Id or Project Number for the Firebase Project. */ diff --git a/firebase-installations/src/main/java/com/google/firebase/installations/Utils.java b/firebase-installations/src/main/java/com/google/firebase/installations/Utils.java index 4b4a592b024..90d257b7884 100644 --- a/firebase-installations/src/main/java/com/google/firebase/installations/Utils.java +++ b/firebase-installations/src/main/java/com/google/firebase/installations/Utils.java @@ -15,6 +15,9 @@ package com.google.firebase.installations; import android.text.TextUtils; + +import androidx.annotation.Nullable; + import com.google.firebase.installations.local.PersistedInstallationEntry; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; @@ -46,11 +49,11 @@ public long currentTimeInSecs() { return TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()); } - static boolean isValidAppIdFormat(String AppId) { - return AppId.contains(APP_ID_IDENTIFICATION_SUBSTRING); + static boolean isValidAppIdFormat(@Nullable String appId) { + return appId.contains(APP_ID_IDENTIFICATION_SUBSTRING); } - static boolean isValidApiKeyFormat(String ApiKey) { - return API_KEY_FORMAT.matcher(ApiKey).matches(); + static boolean isValidApiKeyFormat(@Nullable String apiKey) { + return API_KEY_FORMAT.matcher(apiKey).matches(); } } diff --git a/firebase-installations/src/test/java/com/google/firebase/installations/FirebaseInstallationsTest.java b/firebase-installations/src/test/java/com/google/firebase/installations/FirebaseInstallationsTest.java index 1eb3d0e9417..88c820e46c1 100644 --- a/firebase-installations/src/test/java/com/google/firebase/installations/FirebaseInstallationsTest.java +++ b/firebase-installations/src/test/java/com/google/firebase/installations/FirebaseInstallationsTest.java @@ -1001,6 +1001,8 @@ public void testApiKeyCheck() { assertFalse(Utils.isValidApiKeyFormat("AIzaSyabcdefghijklmno qrstuvwxyzabcdefg")); // wrong char assertFalse( Utils.isValidApiKeyFormat( - "AAAAdpB7anM:APA91bFFK03DIT8y3l5uymwbKcUDJdYqTRSP9Qcxg8SU5kKPalEpObdx0C0xv8gQttdWlLW4hLvvHA0JoDKA6Lrvbi-edUjFCPY_WJkuvHxFwGWXjnj4yI4sPQ27mXuSVIyAbgX4aTK0QYpIKq2j1NBi7ZU75gunQg")); // using FCM server key as API key. + "AAAAdpB7anM:APA91bFFK03DIT8y3l5uymwbKcUDJdYqTRSP9Qcxg8SU5kKPalEpObdx0C0xv8gQttdWlL" + + "W4hLvvHA0JoDKA6Lrvbi-edUjFCPY_WJkuvHxFwGWXjnj4yI4sPQ27mXuSVIyAbgX4aTK0QY" + + "pIKq2j1NBi7ZU75gunQg")); // using FCM server key as API key. } } From d9962f1e5ee377bc36636359e34b503b5afc0e7d Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Tue, 14 Apr 2020 11:13:46 -0700 Subject: [PATCH 3/3] change regex dependency to re2j --- firebase-installations/firebase-installations.gradle | 1 + .../java/com/google/firebase/installations/Utils.java | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/firebase-installations/firebase-installations.gradle b/firebase-installations/firebase-installations.gradle index d44b7af0ab2..57d78c7ce9c 100644 --- a/firebase-installations/firebase-installations.gradle +++ b/firebase-installations/firebase-installations.gradle @@ -44,6 +44,7 @@ dependencies { implementation 'androidx.multidex:multidex:2.0.1' implementation 'com.google.android.gms:play-services-tasks:17.0.0' + implementation 'com.google.re2j:re2j:1.0' compileOnly "com.google.auto.value:auto-value-annotations:1.6.5" diff --git a/firebase-installations/src/main/java/com/google/firebase/installations/Utils.java b/firebase-installations/src/main/java/com/google/firebase/installations/Utils.java index 90d257b7884..5b228527195 100644 --- a/firebase-installations/src/main/java/com/google/firebase/installations/Utils.java +++ b/firebase-installations/src/main/java/com/google/firebase/installations/Utils.java @@ -16,11 +16,12 @@ import android.text.TextUtils; -import androidx.annotation.Nullable; +import androidx.annotation.NonNull; import com.google.firebase.installations.local.PersistedInstallationEntry; import java.util.concurrent.TimeUnit; -import java.util.regex.Pattern; + +import com.google.re2j.Pattern; /** Util methods used for {@link FirebaseInstallations} */ class Utils { @@ -49,11 +50,11 @@ public long currentTimeInSecs() { return TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()); } - static boolean isValidAppIdFormat(@Nullable String appId) { + static boolean isValidAppIdFormat(@NonNull String appId) { return appId.contains(APP_ID_IDENTIFICATION_SUBSTRING); } - static boolean isValidApiKeyFormat(@Nullable String apiKey) { + static boolean isValidApiKeyFormat(@NonNull String apiKey) { return API_KEY_FORMAT.matcher(apiKey).matches(); } }