Skip to content

Commit c0d8076

Browse files
WIP: feat(appcheck-recaptcha-enterprise): Implement RecaptchaEnterpriseAppCheckProvider
Implements the core `AppCheckProvider` for reCAPTCHA Enterprise, orchestrating the attestation and token exchange process. This class: - Initializes the reCAPTCHA Android client using the provided `SiteKey`. - Defines the `getToken()` method to: - Obtain a reCAPTCHA Enterprise attestation token from the Android client. - Exchange this attestation token with the Firebase App Check backend via `NetworkClient` using the `ExchangeRecaptchaEnterpriseTokenRequest` payload. - Convert the backend response into a `DefaultAppCheckToken`. - Utilizes provided executors for asynchronous operations to ensure smooth integration with the Android application lifecycle. Further unit and integration tests are still pending for this implementation.
1 parent c313b71 commit c0d8076

File tree

1 file changed

+100
-0
lines changed

1 file changed

+100
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package com.google.firebase.appcheck.recaptchaenterprise.internal;
2+
3+
import android.app.Application;
4+
5+
import androidx.annotation.NonNull;
6+
import androidx.annotation.VisibleForTesting;
7+
8+
import com.google.android.gms.tasks.Task;
9+
import com.google.android.gms.tasks.Tasks;
10+
import com.google.android.recaptcha.Recaptcha;
11+
import com.google.android.recaptcha.RecaptchaAction;
12+
import com.google.android.recaptcha.RecaptchaTasksClient;
13+
import com.google.firebase.FirebaseApp;
14+
import com.google.firebase.annotations.concurrent.Blocking;
15+
import com.google.firebase.annotations.concurrent.Lightweight;
16+
import com.google.firebase.appcheck.AppCheckProvider;
17+
import com.google.firebase.appcheck.AppCheckToken;
18+
import com.google.firebase.appcheck.internal.DefaultAppCheckToken;
19+
import com.google.firebase.appcheck.internal.NetworkClient;
20+
import com.google.firebase.appcheck.internal.RetryManager;
21+
22+
import java.nio.charset.StandardCharsets;
23+
import java.util.Objects;
24+
import java.util.concurrent.Executor;
25+
26+
public class RecaptchaEnterpriseAppCheckProvider implements AppCheckProvider {
27+
28+
private final RecaptchaAction recaptchaAction = RecaptchaAction.custom("fire_app_check");
29+
private final Task<RecaptchaTasksClient> recaptchaTasksClientTask;
30+
private final Executor liteExecutor;
31+
private final Executor blockingExecutor;
32+
private final RetryManager retryManager;
33+
private final NetworkClient networkClient;
34+
35+
public RecaptchaEnterpriseAppCheckProvider(
36+
@NonNull FirebaseApp firebaseApp,
37+
@NonNull Application application,
38+
@NonNull SiteKey siteKey,
39+
@Lightweight Executor liteExecutor,
40+
@Blocking Executor blockingExecutor) {
41+
this.liteExecutor = liteExecutor;
42+
this.blockingExecutor = blockingExecutor;
43+
this.retryManager = new RetryManager();
44+
this.networkClient = new NetworkClient(firebaseApp);
45+
recaptchaTasksClientTask = Recaptcha.fetchTaskClient(application, siteKey.value());
46+
}
47+
48+
@VisibleForTesting
49+
RecaptchaEnterpriseAppCheckProvider(
50+
@Lightweight Executor liteExecutor,
51+
@Blocking Executor blockingExecutor,
52+
@NonNull RetryManager retryManager,
53+
@NonNull NetworkClient networkClient,
54+
@NonNull RecaptchaTasksClient recaptchaTasksClient) {
55+
this.liteExecutor = liteExecutor;
56+
this.blockingExecutor = blockingExecutor;
57+
this.retryManager = retryManager;
58+
this.networkClient = networkClient;
59+
this.recaptchaTasksClientTask = Tasks.forResult(recaptchaTasksClient);
60+
}
61+
62+
@NonNull
63+
@Override
64+
public Task<AppCheckToken> getToken() {
65+
return getRecaptchaEnterpriseAttestation()
66+
.onSuccessTask(
67+
liteExecutor,
68+
recaptchaEnterpriseToken -> {
69+
ExchangeRecaptchaEnterpriseTokenRequest request =
70+
new ExchangeRecaptchaEnterpriseTokenRequest(recaptchaEnterpriseToken);
71+
return Tasks.call(
72+
blockingExecutor,
73+
() ->
74+
networkClient.exchangeAttestationForAppCheckToken(
75+
request.toJsonString().getBytes(StandardCharsets.UTF_8),
76+
NetworkClient.RECAPTCHA_ENTERPRISE,
77+
retryManager));
78+
})
79+
.onSuccessTask(
80+
liteExecutor,
81+
appCheckTokenResponse ->
82+
Tasks.forResult(
83+
DefaultAppCheckToken.constructFromAppCheckTokenResponse(
84+
appCheckTokenResponse)));
85+
}
86+
87+
@NonNull
88+
private Task<String> getRecaptchaEnterpriseAttestation() {
89+
return recaptchaTasksClientTask.continueWithTask(
90+
blockingExecutor,
91+
task -> {
92+
if (task.isSuccessful()) {
93+
RecaptchaTasksClient client = task.getResult();
94+
return client.executeTask(recaptchaAction);
95+
} else {
96+
throw Objects.requireNonNull(task.getException());
97+
}
98+
});
99+
}
100+
}

0 commit comments

Comments
 (0)