Convert rate limit apis to WebSocket.

This commit is contained in:
Cody Henthorne
2025-03-11 15:22:50 -04:00
committed by Greyson Parrelli
parent 86b2fe9742
commit 61a8636217
14 changed files with 149 additions and 63 deletions

View File

@@ -238,18 +238,6 @@ public class SignalServiceAccountManager {
}
}
public void requestRateLimitPushChallenge() throws IOException {
this.pushServiceSocket.requestRateLimitPushChallenge();
}
public void submitRateLimitPushChallenge(String challenge) throws IOException {
this.pushServiceSocket.submitRateLimitPushChallenge(challenge);
}
public void submitRateLimitRecaptchaChallenge(String challenge, String recaptchaToken) throws IOException {
this.pushServiceSocket.submitRateLimitRecaptchaChallenge(challenge, recaptchaToken);
}
public void cancelInFlightRequests() {
this.pushServiceSocket.cancelInFlightRequests();
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2025 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.signalservice.api.ratelimit
import org.whispersystems.signalservice.api.NetworkResult
import org.whispersystems.signalservice.api.websocket.SignalWebSocket
import org.whispersystems.signalservice.internal.post
import org.whispersystems.signalservice.internal.put
import org.whispersystems.signalservice.internal.websocket.WebSocketRequestMessage
/**
* Calls for requesting and submitting rate limit triggered challenges.
*/
class RateLimitChallengeApi(private val authWebSocket: SignalWebSocket.AuthenticatedWebSocket) {
/**
* Request a push challenge for rate limits.
*
* PUT /v1/challenge/push
* - 200: Success
* - 404: No push token available
* - 413: Submitted non-empty body
* - 429: Too many attempts
*/
fun requestPushChallenge(): NetworkResult<Unit> {
val request = WebSocketRequestMessage.post("/v1/challenge/push", null)
return NetworkResult.fromWebSocketRequest(authWebSocket, request)
}
/**
* Submit a push token to reset rate limits.
*
* PUT /v1/challenge
* - 200: Success
* - 428: Challenge token is invalid
* - 429: Too many attempts
*/
fun submitPushChallenge(challenge: String): NetworkResult<Unit> {
val request = WebSocketRequestMessage.put("/v1/challenge", SubmitPushChallengePayload(challenge))
return NetworkResult.fromWebSocketRequest(authWebSocket, request)
}
/**
* Submit a captcha token to reset rate limits.
*
* PUT /v1/challenge
* - 200: Success
* - 428: Challenge token is invalid
* - 429: Too many attempts
*/
fun submitCaptchaChallenge(challenge: String, token: String): NetworkResult<Unit> {
val request = WebSocketRequestMessage.put("/v1/challenge", SubmitRecaptchaChallengePayload(challenge, token))
return NetworkResult.fromWebSocketRequest(authWebSocket, request)
}
}

View File

@@ -1,4 +1,9 @@
package org.whispersystems.signalservice.internal.push;
/*
* Copyright 2025 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.signalservice.api.ratelimit;
import com.fasterxml.jackson.annotation.JsonProperty;

View File

@@ -1,4 +1,9 @@
package org.whispersystems.signalservice.internal.push;
/*
* Copyright 2025 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.signalservice.api.ratelimit;
import com.fasterxml.jackson.annotation.JsonProperty;

View File

@@ -230,9 +230,6 @@ public class PushServiceSocket {
private static final String GROUPSV2_TOKEN = "/v2/groups/token";
private static final String GROUPSV2_JOINED_AT = "/v2/groups/joined_at_version";
private static final String SUBMIT_RATE_LIMIT_CHALLENGE = "/v1/challenge";
private static final String REQUEST_RATE_LIMIT_PUSH_CHALLENGE = "/v1/challenge/push";
private static final String DONATION_REDEEM_RECEIPT = "/v1/donation/redeem-receipt";
private static final String ARCHIVES_REDEEM_RECEIPT = "/v1/archives/redeem-receipt";
@@ -945,25 +942,6 @@ public class PushServiceSocket {
return JsonUtil.fromJson(response, BackupV3AuthCheckResponse.class);
}
public void requestRateLimitPushChallenge() throws IOException {
makeServiceRequest(REQUEST_RATE_LIMIT_PUSH_CHALLENGE, "POST", "");
}
public void submitRateLimitPushChallenge(String challenge) throws IOException {
String payload = JsonUtil.toJson(new SubmitPushChallengePayload(challenge));
makeServiceRequest(SUBMIT_RATE_LIMIT_CHALLENGE, "PUT", payload, NO_HEADERS, (responseCode, body, getHeader) -> {
if (responseCode == 428) {
throw new CaptchaRejectedException();
}
}, SealedSenderAccess.NONE);
}
public void submitRateLimitRecaptchaChallenge(String challenge, String recaptchaToken) throws IOException {
String payload = JsonUtil.toJson(new SubmitRecaptchaChallengePayload(challenge, recaptchaToken));
makeServiceRequest(SUBMIT_RATE_LIMIT_CHALLENGE, "PUT", payload);
}
public void redeemDonationReceipt(ReceiptCredentialPresentation receiptCredentialPresentation, boolean visible, boolean primary) throws IOException {
String payload = JsonUtil.toJson(new RedeemDonationReceiptRequest(Base64.encodeWithPadding(receiptCredentialPresentation.serialize()), visible, primary));
makeServiceRequest(DONATION_REDEEM_RECEIPT, "POST", payload);