Make the utility method for checking group send credentials blocking

This commit is contained in:
Jon Chambers 2025-03-19 16:59:29 -04:00 committed by Jon Chambers
parent 1f1e4c72ec
commit 5a7f4d8381
3 changed files with 29 additions and 14 deletions

View File

@ -7,7 +7,7 @@ package org.whispersystems.textsecuregcm.grpc;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import io.grpc.Status; import io.grpc.Status;
import io.grpc.StatusException;
import java.time.Clock; import java.time.Clock;
import java.util.List; import java.util.List;
import org.signal.libsignal.protocol.ServiceId; import org.signal.libsignal.protocol.ServiceId;
@ -18,8 +18,6 @@ import org.signal.libsignal.zkgroup.groupsend.GroupSendDerivedKeyPair;
import org.signal.libsignal.zkgroup.groupsend.GroupSendFullToken; import org.signal.libsignal.zkgroup.groupsend.GroupSendFullToken;
import org.whispersystems.textsecuregcm.identity.ServiceIdentifier; import org.whispersystems.textsecuregcm.identity.ServiceIdentifier;
import reactor.core.publisher.Mono;
public class GroupSendTokenUtil { public class GroupSendTokenUtil {
private final ServerSecretParams serverSecretParams; private final ServerSecretParams serverSecretParams;
@ -30,16 +28,17 @@ public class GroupSendTokenUtil {
this.clock = clock; this.clock = clock;
} }
public Mono<Void> checkGroupSendToken(final ByteString serializedGroupSendToken, List<ServiceIdentifier> serviceIdentifiers) { public void checkGroupSendToken(final ByteString serializedGroupSendToken,
final List<ServiceIdentifier> serviceIdentifiers) throws StatusException {
try { try {
final GroupSendFullToken token = new GroupSendFullToken(serializedGroupSendToken.toByteArray()); final GroupSendFullToken token = new GroupSendFullToken(serializedGroupSendToken.toByteArray());
final List<ServiceId> serviceIds = serviceIdentifiers.stream().map(ServiceIdentifier::toLibsignal).toList(); final List<ServiceId> serviceIds = serviceIdentifiers.stream().map(ServiceIdentifier::toLibsignal).toList();
token.verify(serviceIds, clock.instant(), GroupSendDerivedKeyPair.forExpiration(token.getExpiration(), serverSecretParams)); token.verify(serviceIds, clock.instant(), GroupSendDerivedKeyPair.forExpiration(token.getExpiration(), serverSecretParams));
return Mono.empty(); } catch (final InvalidInputException e) {
} catch (InvalidInputException e) { throw Status.INVALID_ARGUMENT.asException();
return Mono.error(Status.INVALID_ARGUMENT.asException());
} catch (VerificationFailedException e) { } catch (VerificationFailedException e) {
return Mono.error(Status.UNAUTHENTICATED.asException()); throw Status.UNAUTHENTICATED.asException();
} }
} }
} }

View File

@ -13,6 +13,7 @@ import java.time.Clock;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import io.grpc.StatusException;
import org.signal.chat.keys.CheckIdentityKeyRequest; import org.signal.chat.keys.CheckIdentityKeyRequest;
import org.signal.chat.keys.CheckIdentityKeyResponse; import org.signal.chat.keys.CheckIdentityKeyResponse;
import org.signal.chat.keys.GetPreKeysAnonymousRequest; import org.signal.chat.keys.GetPreKeysAnonymousRequest;
@ -52,16 +53,24 @@ public class KeysAnonymousGrpcService extends ReactorKeysAnonymousGrpc.KeysAnony
: KeysGrpcHelper.ALL_DEVICES; : KeysGrpcHelper.ALL_DEVICES;
return switch (request.getAuthorizationCase()) { return switch (request.getAuthorizationCase()) {
case GROUP_SEND_TOKEN -> case GROUP_SEND_TOKEN -> {
groupSendTokenUtil.checkGroupSendToken(request.getGroupSendToken(), List.of(serviceIdentifier)) try {
.then(lookUpAccount(serviceIdentifier, Status.NOT_FOUND)) groupSendTokenUtil.checkGroupSendToken(request.getGroupSendToken(), List.of(serviceIdentifier));
yield lookUpAccount(serviceIdentifier, Status.NOT_FOUND)
.flatMap(targetAccount -> KeysGrpcHelper.getPreKeys(targetAccount, serviceIdentifier.identityType(), deviceId, keysManager)); .flatMap(targetAccount -> KeysGrpcHelper.getPreKeys(targetAccount, serviceIdentifier.identityType(), deviceId, keysManager));
} catch (final StatusException e) {
yield Mono.error(e);
}
}
case UNIDENTIFIED_ACCESS_KEY -> case UNIDENTIFIED_ACCESS_KEY ->
lookUpAccount(serviceIdentifier, Status.UNAUTHENTICATED) lookUpAccount(serviceIdentifier, Status.UNAUTHENTICATED)
.flatMap(targetAccount -> .flatMap(targetAccount ->
UnidentifiedAccessUtil.checkUnidentifiedAccess(targetAccount, request.getUnidentifiedAccessKey().toByteArray()) UnidentifiedAccessUtil.checkUnidentifiedAccess(targetAccount, request.getUnidentifiedAccessKey().toByteArray())
? KeysGrpcHelper.getPreKeys(targetAccount, serviceIdentifier.identityType(), deviceId, keysManager) ? KeysGrpcHelper.getPreKeys(targetAccount, serviceIdentifier.identityType(), deviceId, keysManager)
: Mono.error(Status.UNAUTHENTICATED.asException())); : Mono.error(Status.UNAUTHENTICATED.asException()));
default -> Mono.error(Status.INVALID_ARGUMENT.asException()); default -> Mono.error(Status.INVALID_ARGUMENT.asException());
}; };
} }

View File

@ -10,6 +10,7 @@ import io.grpc.Status;
import java.time.Clock; import java.time.Clock;
import java.util.List; import java.util.List;
import io.grpc.StatusException;
import org.signal.chat.profile.CredentialType; import org.signal.chat.profile.CredentialType;
import org.signal.chat.profile.GetExpiringProfileKeyCredentialAnonymousRequest; import org.signal.chat.profile.GetExpiringProfileKeyCredentialAnonymousRequest;
import org.signal.chat.profile.GetExpiringProfileKeyCredentialResponse; import org.signal.chat.profile.GetExpiringProfileKeyCredentialResponse;
@ -59,11 +60,17 @@ public class ProfileAnonymousGrpcService extends ReactorProfileAnonymousGrpc.Pro
} }
final Mono<Account> account = switch (request.getAuthenticationCase()) { final Mono<Account> account = switch (request.getAuthenticationCase()) {
case GROUP_SEND_TOKEN -> case GROUP_SEND_TOKEN -> {
groupSendTokenUtil.checkGroupSendToken(request.getGroupSendToken(), List.of(targetIdentifier)) try {
.then(Mono.fromFuture(() -> accountsManager.getByServiceIdentifierAsync(targetIdentifier))) groupSendTokenUtil.checkGroupSendToken(request.getGroupSendToken(), List.of(targetIdentifier));
yield Mono.fromFuture(() -> accountsManager.getByServiceIdentifierAsync(targetIdentifier))
.flatMap(Mono::justOrEmpty) .flatMap(Mono::justOrEmpty)
.switchIfEmpty(Mono.error(Status.NOT_FOUND.asException())); .switchIfEmpty(Mono.error(Status.NOT_FOUND.asException()));
} catch (final StatusException e) {
yield Mono.error(e);
}
}
case UNIDENTIFIED_ACCESS_KEY -> case UNIDENTIFIED_ACCESS_KEY ->
getTargetAccountAndValidateUnidentifiedAccess(targetIdentifier, request.getUnidentifiedAccessKey().toByteArray()); getTargetAccountAndValidateUnidentifiedAccess(targetIdentifier, request.getUnidentifiedAccessKey().toByteArray());
default -> Mono.error(Status.INVALID_ARGUMENT.asException()); default -> Mono.error(Status.INVALID_ARGUMENT.asException());