mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-20 18:28:10 +01:00
Profile gRPC: Define getExpiringProfileKeyCredential endpoint
This commit is contained in:
@@ -1,11 +1,15 @@
|
||||
package org.whispersystems.textsecuregcm.grpc;
|
||||
|
||||
import io.grpc.Status;
|
||||
import org.signal.chat.profile.CredentialType;
|
||||
import org.signal.chat.profile.GetExpiringProfileKeyCredentialAnonymousRequest;
|
||||
import org.signal.chat.profile.GetExpiringProfileKeyCredentialResponse;
|
||||
import org.signal.chat.profile.GetUnversionedProfileAnonymousRequest;
|
||||
import org.signal.chat.profile.GetUnversionedProfileResponse;
|
||||
import org.signal.chat.profile.GetVersionedProfileAnonymousRequest;
|
||||
import org.signal.chat.profile.GetVersionedProfileResponse;
|
||||
import org.signal.chat.profile.ReactorProfileAnonymousGrpc;
|
||||
import org.signal.libsignal.zkgroup.profiles.ServerZkProfileOperations;
|
||||
import org.whispersystems.textsecuregcm.auth.UnidentifiedAccessUtil;
|
||||
import org.whispersystems.textsecuregcm.badges.ProfileBadgeConverter;
|
||||
import org.whispersystems.textsecuregcm.identity.IdentityType;
|
||||
@@ -19,14 +23,17 @@ public class ProfileAnonymousGrpcService extends ReactorProfileAnonymousGrpc.Pro
|
||||
private final AccountsManager accountsManager;
|
||||
private final ProfilesManager profilesManager;
|
||||
private final ProfileBadgeConverter profileBadgeConverter;
|
||||
private final ServerZkProfileOperations zkProfileOperations;
|
||||
|
||||
public ProfileAnonymousGrpcService(
|
||||
final AccountsManager accountsManager,
|
||||
final ProfilesManager profilesManager,
|
||||
final ProfileBadgeConverter profileBadgeConverter) {
|
||||
final ProfileBadgeConverter profileBadgeConverter,
|
||||
final ServerZkProfileOperations zkProfileOperations) {
|
||||
this.accountsManager = accountsManager;
|
||||
this.profilesManager = profilesManager;
|
||||
this.profileBadgeConverter = profileBadgeConverter;
|
||||
this.zkProfileOperations = zkProfileOperations;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -58,10 +65,28 @@ public class ProfileAnonymousGrpcService extends ReactorProfileAnonymousGrpc.Pro
|
||||
.flatMap(targetAccount -> ProfileGrpcHelper.getVersionedProfile(targetAccount, profilesManager, request.getRequest().getVersion()));
|
||||
}
|
||||
|
||||
private Mono<Account> getTargetAccountAndValidateUnidentifiedAccess(final ServiceIdentifier targetIdentifier, final byte[] unidentifiedAccessKey) {
|
||||
return Mono.fromFuture(() -> accountsManager.getByServiceIdentifierAsync(targetIdentifier))
|
||||
.flatMap(Mono::justOrEmpty)
|
||||
.filter(targetAccount -> UnidentifiedAccessUtil.checkUnidentifiedAccess(targetAccount, unidentifiedAccessKey))
|
||||
.switchIfEmpty(Mono.error(Status.UNAUTHENTICATED.asException()));
|
||||
@Override
|
||||
public Mono<GetExpiringProfileKeyCredentialResponse> getExpiringProfileKeyCredential(
|
||||
final GetExpiringProfileKeyCredentialAnonymousRequest request) {
|
||||
final ServiceIdentifier targetIdentifier = ServiceIdentifierUtil.fromGrpcServiceIdentifier(request.getRequest().getAccountIdentifier());
|
||||
|
||||
if (targetIdentifier.identityType() != IdentityType.ACI) {
|
||||
throw Status.INVALID_ARGUMENT.withDescription("Expected ACI service identifier").asRuntimeException();
|
||||
}
|
||||
|
||||
if (request.getRequest().getCredentialType() != CredentialType.CREDENTIAL_TYPE_EXPIRING_PROFILE_KEY) {
|
||||
throw Status.INVALID_ARGUMENT.withDescription("Expected expiring profile key credential type").asRuntimeException();
|
||||
}
|
||||
|
||||
return getTargetAccountAndValidateUnidentifiedAccess(targetIdentifier, request.getUnidentifiedAccessKey().toByteArray())
|
||||
.flatMap(account -> ProfileGrpcHelper.getExpiringProfileKeyCredentialResponse(account.getUuid(),
|
||||
request.getRequest().getVersion(), request.getRequest().getCredentialRequest().toByteArray(), profilesManager, zkProfileOperations));
|
||||
}
|
||||
|
||||
private Mono<Account> getTargetAccountAndValidateUnidentifiedAccess(final ServiceIdentifier targetIdentifier, final byte[] unidentifiedAccessKey) {
|
||||
return Mono.fromFuture(() -> accountsManager.getByServiceIdentifierAsync(targetIdentifier))
|
||||
.flatMap(Mono::justOrEmpty)
|
||||
.filter(targetAccount -> UnidentifiedAccessUtil.checkUnidentifiedAccess(targetAccount, unidentifiedAccessKey))
|
||||
.switchIfEmpty(Mono.error(Status.UNAUTHENTICATED.asException()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,15 @@ import java.util.UUID;
|
||||
import io.grpc.Status;
|
||||
import org.signal.chat.profile.Badge;
|
||||
import org.signal.chat.profile.BadgeSvg;
|
||||
import org.signal.chat.profile.GetExpiringProfileKeyCredentialResponse;
|
||||
import org.signal.chat.profile.GetUnversionedProfileResponse;
|
||||
import org.signal.chat.profile.GetVersionedProfileResponse;
|
||||
import org.signal.chat.profile.UserCapabilities;
|
||||
import org.signal.libsignal.protocol.ServiceId;
|
||||
import org.signal.libsignal.zkgroup.InvalidInputException;
|
||||
import org.signal.libsignal.zkgroup.VerificationFailedException;
|
||||
import org.signal.libsignal.zkgroup.profiles.ExpiringProfileKeyCredentialResponse;
|
||||
import org.signal.libsignal.zkgroup.profiles.ServerZkProfileOperations;
|
||||
import org.whispersystems.textsecuregcm.auth.UnidentifiedAccessChecksum;
|
||||
import org.whispersystems.textsecuregcm.badges.ProfileBadgeConverter;
|
||||
import org.whispersystems.textsecuregcm.identity.AciServiceIdentifier;
|
||||
@@ -119,4 +125,28 @@ public class ProfileGrpcHelper {
|
||||
|
||||
return responseBuilder.build();
|
||||
}
|
||||
|
||||
static Mono<GetExpiringProfileKeyCredentialResponse> getExpiringProfileKeyCredentialResponse(
|
||||
final UUID targetUuid,
|
||||
final String version,
|
||||
final byte[] encodedCredentialRequest,
|
||||
final ProfilesManager profilesManager,
|
||||
final ServerZkProfileOperations zkProfileOperations) {
|
||||
return Mono.fromFuture(profilesManager.getAsync(targetUuid, version))
|
||||
.flatMap(Mono::justOrEmpty)
|
||||
.map(profile -> {
|
||||
final ExpiringProfileKeyCredentialResponse profileKeyCredentialResponse;
|
||||
try {
|
||||
profileKeyCredentialResponse = ProfileHelper.getExpiringProfileKeyCredential(encodedCredentialRequest,
|
||||
profile, new ServiceId.Aci(targetUuid), zkProfileOperations);
|
||||
} catch (VerificationFailedException | InvalidInputException e) {
|
||||
throw Status.INVALID_ARGUMENT.withCause(e).asRuntimeException();
|
||||
}
|
||||
|
||||
return GetExpiringProfileKeyCredentialResponse.newBuilder()
|
||||
.setProfileKeyCredential(ByteString.copyFrom(profileKeyCredentialResponse.serialize()))
|
||||
.build();
|
||||
})
|
||||
.switchIfEmpty(Mono.error(Status.NOT_FOUND.withDescription("Profile version not found").asException()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@ package org.whispersystems.textsecuregcm.grpc;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import io.grpc.Status;
|
||||
import org.signal.chat.profile.CredentialType;
|
||||
import org.signal.chat.profile.GetExpiringProfileKeyCredentialRequest;
|
||||
import org.signal.chat.profile.GetExpiringProfileKeyCredentialResponse;
|
||||
import org.signal.chat.profile.GetUnversionedProfileRequest;
|
||||
import org.signal.chat.profile.GetUnversionedProfileResponse;
|
||||
import org.signal.chat.profile.GetVersionedProfileRequest;
|
||||
@@ -11,6 +14,7 @@ import org.signal.chat.profile.ProfileAvatarUploadAttributes;
|
||||
import org.signal.chat.profile.ReactorProfileGrpc;
|
||||
import org.signal.chat.profile.SetProfileRequest;
|
||||
import org.signal.chat.profile.SetProfileResponse;
|
||||
import org.signal.libsignal.zkgroup.profiles.ServerZkProfileOperations;
|
||||
import org.whispersystems.textsecuregcm.auth.grpc.AuthenticatedDevice;
|
||||
import org.whispersystems.textsecuregcm.auth.grpc.AuthenticationUtil;
|
||||
import org.whispersystems.textsecuregcm.badges.ProfileBadgeConverter;
|
||||
@@ -56,6 +60,7 @@ public class ProfileGrpcService extends ReactorProfileGrpc.ProfileImplBase {
|
||||
private final PolicySigner policySigner;
|
||||
private final ProfileBadgeConverter profileBadgeConverter;
|
||||
private final RateLimiters rateLimiters;
|
||||
private final ServerZkProfileOperations zkProfileOperations;
|
||||
private final String bucket;
|
||||
|
||||
private record AvatarData(Optional<String> currentAvatar,
|
||||
@@ -73,6 +78,7 @@ public class ProfileGrpcService extends ReactorProfileGrpc.ProfileImplBase {
|
||||
final PolicySigner policySigner,
|
||||
final ProfileBadgeConverter profileBadgeConverter,
|
||||
final RateLimiters rateLimiters,
|
||||
final ServerZkProfileOperations zkProfileOperations,
|
||||
final String bucket) {
|
||||
this.clock = clock;
|
||||
this.accountsManager = accountsManager;
|
||||
@@ -85,6 +91,7 @@ public class ProfileGrpcService extends ReactorProfileGrpc.ProfileImplBase {
|
||||
this.policySigner = policySigner;
|
||||
this.profileBadgeConverter = profileBadgeConverter;
|
||||
this.rateLimiters = rateLimiters;
|
||||
this.zkProfileOperations = zkProfileOperations;
|
||||
this.bucket = bucket;
|
||||
}
|
||||
|
||||
@@ -186,6 +193,26 @@ public class ProfileGrpcService extends ReactorProfileGrpc.ProfileImplBase {
|
||||
.flatMap(account -> ProfileGrpcHelper.getVersionedProfile(account, profilesManager, request.getVersion()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<GetExpiringProfileKeyCredentialResponse> getExpiringProfileKeyCredential(
|
||||
final GetExpiringProfileKeyCredentialRequest request) {
|
||||
final AuthenticatedDevice authenticatedDevice = AuthenticationUtil.requireAuthenticatedDevice();
|
||||
final ServiceIdentifier targetIdentifier = ServiceIdentifierUtil.fromGrpcServiceIdentifier(request.getAccountIdentifier());
|
||||
|
||||
if (targetIdentifier.identityType() != IdentityType.ACI) {
|
||||
throw Status.INVALID_ARGUMENT.withDescription("Expected ACI service identifier").asRuntimeException();
|
||||
}
|
||||
|
||||
if (request.getCredentialType() != CredentialType.CREDENTIAL_TYPE_EXPIRING_PROFILE_KEY) {
|
||||
throw Status.INVALID_ARGUMENT.withDescription("Expected expiring profile key credential type").asRuntimeException();
|
||||
}
|
||||
|
||||
return validateRateLimitAndGetAccount(authenticatedDevice.accountIdentifier(), targetIdentifier)
|
||||
.flatMap(targetAccount -> ProfileGrpcHelper.getExpiringProfileKeyCredentialResponse(targetAccount.getUuid(),
|
||||
request.getVersion(), request.getCredentialRequest().toByteArray(), profilesManager, zkProfileOperations));
|
||||
}
|
||||
|
||||
|
||||
private Mono<Account> validateRateLimitAndGetAccount(final UUID requesterUuid,
|
||||
final ServiceIdentifier targetIdentifier) {
|
||||
return rateLimiters.getProfileLimiter().validateReactive(requesterUuid)
|
||||
|
||||
Reference in New Issue
Block a user