diff --git a/firebase-installations/firebase-installations.gradle b/firebase-installations/firebase-installations.gradle index 39b289c0834..0ef070e8b6d 100644 --- a/firebase-installations/firebase-installations.gradle +++ b/firebase-installations/firebase-installations.gradle @@ -52,6 +52,8 @@ dependencies { testImplementation 'androidx.test:core:1.2.0' testImplementation 'junit:junit:4.12' testImplementation "org.robolectric:robolectric:$robolectricVersion" + testImplementation "com.google.truth:truth:$googleTruthVersion" + androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test:runner:1.2.0' diff --git a/firebase-installations/src/main/java/com/google/firebase/installations/remote/FirebaseInstallationServiceClient.java b/firebase-installations/src/main/java/com/google/firebase/installations/remote/FirebaseInstallationServiceClient.java index 51cc1869fae..e1a6facd6f5 100644 --- a/firebase-installations/src/main/java/com/google/firebase/installations/remote/FirebaseInstallationServiceClient.java +++ b/firebase-installations/src/main/java/com/google/firebase/installations/remote/FirebaseInstallationServiceClient.java @@ -15,6 +15,7 @@ package com.google.firebase.installations.remote; import static android.content.ContentValues.TAG; +import static com.google.android.gms.common.internal.Preconditions.checkArgument; import android.content.Context; import android.content.pm.PackageManager; @@ -23,12 +24,13 @@ import androidx.annotation.NonNull; import com.google.android.gms.common.util.AndroidUtilsLight; import com.google.android.gms.common.util.Hex; +import com.google.android.gms.common.util.VisibleForTesting; import com.google.firebase.installations.InstallationTokenResult; import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; import java.nio.charset.Charset; -import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; import java.util.zip.GZIPOutputStream; import javax.net.ssl.HttpsURLConnection; import org.json.JSONException; @@ -61,6 +63,11 @@ public class FirebaseInstallationServiceClient { private static final int NETWORK_TIMEOUT_MILLIS = 10000; + private static final Pattern EXPIRATION_TIMESTAMP_PATTERN = Pattern.compile("[0-9]+s"); + + @VisibleForTesting + static final String PARSING_EXPIRATION_TIME_ERROR_MESSAGE = "Invalid Expiration Timestamp."; + private final Context context; public FirebaseInstallationServiceClient(@NonNull Context context) { @@ -273,7 +280,7 @@ private InstallationResponse readCreateResponse(HttpsURLConnection conn) throws installationTokenResult.setToken(reader.nextString()); } else if (key.equals("expiresIn")) { installationTokenResult.setTokenExpirationInSecs( - TimeUnit.MILLISECONDS.toSeconds(reader.nextLong())); + parseTokenExpirationTimestamp(reader.nextString())); } else { reader.skipValue(); } @@ -301,7 +308,7 @@ private InstallationTokenResult readGenerateAuthTokenResponse(HttpsURLConnection if (name.equals("token")) { builder.setToken(reader.nextString()); } else if (name.equals("expiresIn")) { - builder.setTokenExpirationInSecs(TimeUnit.MILLISECONDS.toSeconds(reader.nextLong())); + builder.setTokenExpirationInSecs(parseTokenExpirationTimestamp(reader.nextString())); } else { reader.skipValue(); } @@ -329,4 +336,19 @@ private String getFingerprintHashForPackage() { return null; } } + + /** + * Returns parsed token expiration timestamp in seconds. + * + * @param expiresIn is expiration timestamp in String format: 604800s + */ + @VisibleForTesting + static long parseTokenExpirationTimestamp(String expiresIn) { + checkArgument( + EXPIRATION_TIMESTAMP_PATTERN.matcher(expiresIn).matches(), + PARSING_EXPIRATION_TIME_ERROR_MESSAGE); + return (expiresIn == null || expiresIn.length() == 0) + ? 0L + : Long.parseLong(expiresIn.substring(0, expiresIn.length() - 1)); + } } diff --git a/firebase-installations/src/test/java/com/google/firebase/installations/remote/FirebaseInstallationServiceClientTest.java b/firebase-installations/src/test/java/com/google/firebase/installations/remote/FirebaseInstallationServiceClientTest.java new file mode 100644 index 00000000000..eb30312c0e4 --- /dev/null +++ b/firebase-installations/src/test/java/com/google/firebase/installations/remote/FirebaseInstallationServiceClientTest.java @@ -0,0 +1,55 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.firebase.installations.remote; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; +import static org.junit.Assert.fail; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +/** Tests for {@link FirebaseInstallationServiceClient}. */ +@RunWith(RobolectricTestRunner.class) +public class FirebaseInstallationServiceClientTest { + + private final String TEST_EXPIRATION_TIMESTAMP = "604800s"; + private final long TEST_EXPIRATION_IN_SECS = 604800; + private final String INCORRECT_EXPIRATION_TIMESTAMP = "2345"; + + @Test + public void parseTokenExpirationTimestamp_successful() { + long actual = + FirebaseInstallationServiceClient.parseTokenExpirationTimestamp(TEST_EXPIRATION_TIMESTAMP); + + assertWithMessage("Exception status doesn't match") + .that(actual) + .isEqualTo(TEST_EXPIRATION_IN_SECS); + } + + @Test + public void parseTokenExpirationTimestamp_failed() { + try { + FirebaseInstallationServiceClient.parseTokenExpirationTimestamp( + INCORRECT_EXPIRATION_TIMESTAMP); + fail("Parsing token expiration timestamp failed."); + } catch (IllegalArgumentException expected) { + assertThat(expected) + .hasMessageThat() + .isEqualTo(FirebaseInstallationServiceClient.PARSING_EXPIRATION_TIME_ERROR_MESSAGE); + } + } +}