mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-19 00:18:42 +01:00
Avoid reading modified account when generating backup credentials
This commit is contained in:
committed by
ravi-signal
parent
368e705b68
commit
5850eeb87b
@@ -14,7 +14,9 @@ import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
@@ -184,13 +186,11 @@ public class BackupAuthManager {
|
||||
* method will also remove the expired voucher from the account.
|
||||
*
|
||||
* @param account The account to create the credentials for
|
||||
* @param credentialType The type of backup credentials to create
|
||||
* @param redemptionRange The time range to return credentials for
|
||||
* @return Credentials and the day on which they may be redeemed
|
||||
*/
|
||||
public List<Credential> getBackupAuthCredentials(
|
||||
public Map<BackupCredentialType, List<Credential>> getBackupAuthCredentials(
|
||||
final Account account,
|
||||
final BackupCredentialType credentialType,
|
||||
final RedemptionRange redemptionRange) throws BackupNotFoundException {
|
||||
|
||||
// If the account has an expired payment, clear it before continuing
|
||||
@@ -201,31 +201,35 @@ public class BackupAuthManager {
|
||||
a.setBackupVoucher(null);
|
||||
}
|
||||
});
|
||||
return getBackupAuthCredentials(updated, credentialType, redemptionRange);
|
||||
}
|
||||
|
||||
// fetch the blinded backup-id the account should have previously committed to
|
||||
final byte[] committedBytes = account.getBackupCredentialRequest(credentialType)
|
||||
.orElseThrow(() -> new BackupNotFoundException("No blinded backup-id has been added to the account"));
|
||||
final Map<BackupCredentialType, List<Credential>> credentials = new HashMap<>();
|
||||
for (BackupCredentialType credentialType : BackupCredentialType.values()) {
|
||||
// fetch the blinded backup-id the account should have previously committed to
|
||||
final byte[] committedBytes = account.getBackupCredentialRequest(credentialType)
|
||||
.orElseThrow(() -> new BackupNotFoundException("No blinded backup-id has been added to the account"));
|
||||
|
||||
try {
|
||||
final BackupLevel defaultBackupLevel = configuredBackupLevel(account);
|
||||
try {
|
||||
final BackupLevel defaultBackupLevel = configuredBackupLevel(account);
|
||||
|
||||
// create a credential for every day in the requested period
|
||||
final BackupAuthCredentialRequest credentialReq = new BackupAuthCredentialRequest(committedBytes);
|
||||
return StreamSupport.stream(redemptionRange.spliterator(), false)
|
||||
.map(redemptionTime -> {
|
||||
// Check if the account has a voucher that's good for a certain receiptLevel at redemption time, otherwise
|
||||
// use the default receipt level
|
||||
final BackupLevel backupLevel = storedBackupLevel(account, redemptionTime).orElse(defaultBackupLevel);
|
||||
return new Credential(
|
||||
credentialReq.issueCredential(redemptionTime, backupLevel, credentialType, serverSecretParams),
|
||||
redemptionTime);
|
||||
})
|
||||
.toList();
|
||||
} catch (InvalidInputException e) {
|
||||
throw new UncheckedIOException(new IOException("Could not deserialize stored request credential", e));
|
||||
// create a credential for every day in the requested period
|
||||
final BackupAuthCredentialRequest credentialReq = new BackupAuthCredentialRequest(committedBytes);
|
||||
final List<Credential> credentialList = StreamSupport.stream(redemptionRange.spliterator(), false)
|
||||
.map(redemptionTime -> {
|
||||
// Check if the account has a voucher that's good for a certain receiptLevel at redemption time, otherwise
|
||||
// use the default receipt level
|
||||
final BackupLevel backupLevel = storedBackupLevel(account, redemptionTime).orElse(defaultBackupLevel);
|
||||
return new Credential(
|
||||
credentialReq.issueCredential(redemptionTime, backupLevel, credentialType, serverSecretParams),
|
||||
redemptionTime);
|
||||
})
|
||||
.toList();
|
||||
credentials.put(credentialType, credentialList);
|
||||
} catch (InvalidInputException e) {
|
||||
throw new UncheckedIOException(new IOException("Could not deserialize stored request credential", e));
|
||||
}
|
||||
}
|
||||
return credentials;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,6 +15,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.net.HttpHeaders;
|
||||
import io.dropwizard.auth.Auth;
|
||||
import io.micrometer.core.instrument.Tag;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
@@ -48,7 +49,6 @@ import java.lang.annotation.Target;
|
||||
import java.time.Clock;
|
||||
import java.time.Instant;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@@ -312,9 +312,6 @@ public class ArchiveController {
|
||||
@NotNull @QueryParam("redemptionStartSeconds") Long startSeconds,
|
||||
@NotNull @QueryParam("redemptionEndSeconds") Long endSeconds) throws BackupNotFoundException {
|
||||
|
||||
final Map<BackupCredentialType, List<BackupAuthCredentialsResponse.BackupAuthCredential>> credentialsByType =
|
||||
new HashMap<>();
|
||||
|
||||
final RedemptionRange redemptionRange;
|
||||
try {
|
||||
redemptionRange = RedemptionRange.inclusive(Clock.systemUTC(), Instant.ofEpochSecond(startSeconds), Instant.ofEpochSecond(endSeconds));
|
||||
@@ -325,23 +322,20 @@ public class ArchiveController {
|
||||
final Account account = accountsManager.getByAccountIdentifier(authenticatedDevice.accountIdentifier())
|
||||
.orElseThrow(() -> new WebApplicationException(Response.Status.UNAUTHORIZED));
|
||||
|
||||
for (BackupCredentialType credentialType : BackupCredentialType.values()) {
|
||||
final List<BackupAuthManager.Credential> credentials =
|
||||
backupAuthManager.getBackupAuthCredentials(account, credentialType, redemptionRange);
|
||||
backupMetrics.updateGetCredentialCounter(
|
||||
UserAgentTagUtil.getPlatformTag(userAgent),
|
||||
credentialType,
|
||||
credentials.size());
|
||||
credentialsByType.put(credentialType, credentials.stream()
|
||||
.map(credential -> new BackupAuthCredentialsResponse.BackupAuthCredential(
|
||||
credential.credential().serialize(),
|
||||
credential.redemptionTime().getEpochSecond()))
|
||||
.toList());
|
||||
}
|
||||
return new BackupAuthCredentialsResponse(credentialsByType.entrySet().stream()
|
||||
.collect(Collectors.toMap(
|
||||
final Map<BackupCredentialType, List<BackupAuthManager.Credential>> credentials =
|
||||
backupAuthManager.getBackupAuthCredentials(account, redemptionRange);
|
||||
|
||||
final Tag platformTag = UserAgentTagUtil.getPlatformTag(userAgent);
|
||||
credentials.forEach((type, credentialList) ->
|
||||
backupMetrics.updateGetCredentialCounter(platformTag, type, credentialList.size()));
|
||||
|
||||
return new BackupAuthCredentialsResponse(credentials.entrySet().stream().collect(Collectors.toMap(
|
||||
e -> BackupAuthCredentialsResponse.CredentialType.fromLibsignalType(e.getKey()),
|
||||
Map.Entry::getValue)));
|
||||
e -> e.getValue().stream()
|
||||
.map(credential -> new BackupAuthCredentialsResponse.BackupAuthCredential(
|
||||
credential.credential().serialize(),
|
||||
credential.redemptionTime().getEpochSecond()))
|
||||
.toList())));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import io.micrometer.core.instrument.Tag;
|
||||
import java.time.Clock;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import org.signal.chat.backup.GetBackupAuthCredentialsRequest;
|
||||
@@ -106,19 +107,14 @@ public class BackupsGrpcService extends SimpleBackupsGrpc.BackupsImplBase {
|
||||
}
|
||||
final Account account = authenticatedAccount();
|
||||
try {
|
||||
final List<BackupAuthManager.Credential> messageCredentials =
|
||||
backupAuthManager.getBackupAuthCredentials(
|
||||
account,
|
||||
BackupCredentialType.MESSAGES,
|
||||
redemptionRange);
|
||||
backupMetrics.updateGetCredentialCounter(platformTag, BackupCredentialType.MESSAGES, messageCredentials.size());
|
||||
|
||||
final List<BackupAuthManager.Credential> mediaCredentials =
|
||||
backupAuthManager.getBackupAuthCredentials(
|
||||
account,
|
||||
BackupCredentialType.MEDIA,
|
||||
redemptionRange);
|
||||
backupMetrics.updateGetCredentialCounter(platformTag, BackupCredentialType.MEDIA, mediaCredentials.size());
|
||||
final Map<BackupCredentialType, List<BackupAuthManager.Credential>> credentials =
|
||||
backupAuthManager.getBackupAuthCredentials(account, redemptionRange);
|
||||
|
||||
credentials.forEach((type, credentialList) ->
|
||||
backupMetrics.updateGetCredentialCounter(platformTag, type, credentialList.size()));
|
||||
final List<BackupAuthManager.Credential> messageCredentials = credentials.get(BackupCredentialType.MESSAGES);
|
||||
final List<BackupAuthManager.Credential> mediaCredentials = credentials.get(BackupCredentialType.MEDIA);
|
||||
|
||||
return GetBackupAuthCredentialsResponse.newBuilder()
|
||||
.setCredentials(GetBackupAuthCredentialsResponse.Credentials.newBuilder()
|
||||
|
||||
Reference in New Issue
Block a user